Я хочу создать статический класс в PHP и заставить его вести себя так же, как в C#, поэтому
Что-то в этом роде ...
static class Hello {
private static $greeting = 'Hello';
private __construct() {
$greeting .= ' There!';
}
public static greet(){
echo $greeting;
}
}
Hello::greet(); // Hello There!
Просто высказываю свое собственное мнение, но, исходя из моего опыта работы с PHP, для здравомыслия, тестируемости и масштабируемости статические классы должны в значительной степени полностью не иметь состояния, представлять более функциональный API-интерфейс, подобный программированию, чем объектно-ориентированный, и, как правило, лучше всего использовать в качестве фасадов доступности для полностью созданных объектов или служебных оболочек для помощников или аналогичных конструкций, если они вообще используются.






У вас могут быть статические классы в PHP, но они не вызывают конструктор автоматически (если вы попытаетесь вызвать self::__construct(), вы получите сообщение об ошибке).
Поэтому вам нужно будет создать функцию initialize() и вызывать ее в каждом методе:
<?php
class Hello
{
private static $greeting = 'Hello';
private static $initialized = false;
private static function initialize()
{
if (self::$initialized)
return;
self::$greeting .= ' There!';
self::$initialized = true;
}
public static function greet()
{
self::initialize();
echo self::$greeting;
}
}
Hello::greet(); // Hello There!
?>
Я довольно часто делаю это, просто чтобы собрать все функции в одном месте. IE Utility :: doSomethingUseful ();
Вместо Therefore you'd have to create an initialize() function and call it in each method: было бы проще сделать initialize общедоступной функцией и вызывать ее сразу после объявления класса.
Я знаю, что это довольно давно, но теперь вы можете использовать магию __callStatic, поэтому, когда вы вызываете какой-либо статический метод или что-то еще, он сначала вызывает __callStatic, там вы можете увидеть, инициализирован ли он, а затем выполнить self::$method или что-то еще, что вы вызываете. Если он по-прежнему вызывает метод напрямую, попробуйте изменить все на частное и посмотрите там.
Что произойдет, если два потока вызовут приветствие одновременно? Поскольку нет синхронизации, инициализация не будет вызываться дважды (что в этом случае нормально, но во многих других случаях - нет). Или php однопоточный и не вытесняющий, как node?
Мне понравилось, как вы это сделали. Фантастический.
у вас могут быть эти «статические» классы. но я полагаю, что чего-то действительно важного не хватает: в php у вас нет цикла приложения, поэтому вы не получите настоящую статику (или синглтон) во всем приложении ...
см. Синглтон в PHP
Статические классы и синглтоны - это всего лишь две разные вещи.
final Class B{
static $staticVar;
static function getA(){
self::$staticVar = New A;
}
}
структура b называется обработчиком single, вы также можете сделать это в
Class a{
static $instance;
static function getA(...){
if (!isset(self::$staticVar)){
self::$staticVar = New A(...);
}
return self::$staticVar;
}
}
это одноэлементное использование
$a = a::getA(...);
объект не может быть определен статически но это работает
final Class B{
static $var;
static function init(){
self::$var = new A();
}
B::init();
Андреас Нидермайр: вот как работает php (app-cycle = одиночный запрос). Но синглтон (на том, который находится в запросе) - это возможность в php (в php синглтон - это объект, имеющий 1 экземпляр (внутри приложения- цикл)
В дополнение к ответу Грега я бы рекомендовал установить конструктор закрытым, чтобы невозможно было создать экземпляр класса.
По моему скромному мнению, это более полный пример, основанный на примере Грега:
<?php
class Hello
{
/**
* Construct won't be called inside this class and is uncallable from
* the outside. This prevents instantiating this class.
* This is by purpose, because we want a static class.
*/
private function __construct() {}
private static $greeting = 'Hello';
private static $initialized = false;
private static function initialize()
{
if (self::$initialized)
return;
self::$greeting .= ' There!';
self::$initialized = true;
}
public static function greet()
{
self::initialize();
echo self::$greeting;
}
}
Hello::greet(); // Hello There!
?>
Это отличный подход, однако функция построения не может быть реализована, если ваш одиночный элемент наследуется от определенных объектов, которым требуется общедоступный конструктор.
@EricHerlitz Этот вопрос не о синглтонах, а о статических классах. Зачем вам создавать статический класс, наследующий от класса, который должен быть создан?
В равной степени объявление класса как абстрактного с предотвращением его создания экземпляров и по-прежнему разрешает вызовы статических методов.
Обычно я предпочитаю писать обычные нестатические классы и использовать фабричный класс для создания отдельных (sudo static) экземпляров объекта.
Таким образом, конструктор и деструктор работают как обычно, и я могу создавать дополнительные нестатические экземпляры, если хочу (например, второе соединение с БД)
Я использую это все время, и это особенно полезно для создания пользовательских обработчиков сеансов хранилища БД, так как при завершении страницы деструктор отправит сеанс в базу данных.
Еще одно преимущество заключается в том, что вы можете игнорировать порядок вызова, поскольку все будет настроено по запросу.
class Factory {
static function &getDB ($construct_params = null)
{
static $instance;
if ( ! is_object($instance) )
{
include_once("clsDB.php");
$instance = new clsDB($construct_params); // constructor will be called
}
return $instance;
}
}
Класс БД ...
class clsDB {
$regular_public_variables = "whatever";
function __construct($construct_params) {...}
function __destruct() {...}
function getvar() { return $this->regular_public_variables; }
}
Везде, где вы хотите его использовать, просто позвоните ...
$static_instance = &Factory::getDB($somekickoff);
Затем просто рассматривайте все методы как нестатические (потому что они есть)
echo $static_instance->getvar();
На самом деле это реализация одноэлементного шаблона, и ее на самом деле не следует использовать - вместо этого используйте внедрение зависимостей, которое можно тестировать и упрощает отладку.
Можете ли вы привести пример того, как использовать инъекцию зависимостей для этого ответа и как это сделать его более тестируемым?
Не могли бы вы вкратце объяснить, как должен вести себя статический класс? Это реализация утилиты?