Чи можливо створити статичні класи в PHP (наприклад, у C #)?


139

Я хочу створити статичний клас у PHP, щоб він поводився так, як це робиться в C #, так

  1. Конструктор автоматично викликається при першому виклику до класу
  2. Ніяких екземплярів не потрібно

Щось такого роду ...

static class Hello {
    private static $greeting = 'Hello';

    private __construct() {
        $greeting .= ' There!';
    }

    public static greet(){
        echo $greeting;
    }
}

Hello::greet(); // Hello There!

Не могли б ви коротко пояснити, як має вести себе статичний клас? Це реалізація утиліти?
xtofl

Просто кидаю туди свою власну думку, але з мого досвіду роботи в PHP, для розуму, перевіряемості та масштабованості, статичні класи повинні бути майже повністю бездержавними, представляти більш функціональні програми, схожі на програмування, ніж об'єктно-орієнтовані, і взагалі є найкраще використовувати в якості фасадів доступності для об'єктів, що повністю розробляються, або утилітних обгортків для помічників або подібних конструкцій, якщо вони взагалі використовуються.
мопсид

Відповіді:


200

Ви можете мати статичні класи в 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!


?>

20
Я досить часто роблю це лише для того, щоб згорнути всі функції в одному місці. IE Utility :: doSomethingUseful ();
smack0007

16
Замість Therefore you'd have to create an initialize() function and call it in each method:цього було б простіше зробити initializeпублічну функцію та викликати її відразу після оголошення класу.
чача15

4
Я знаю, що це досить старе, але тепер ви можете використовувати магію __callStatic, тож коли ви зателефонуєте будь-яким статичним методом чи будь-чим іншим, він спочатку зателефонує __callStatic, там ви зможете побачити, чи він був ініціалізований, а потім зробіть self::$methodчи все, що ви викликаєте. Якщо він все ще безпосередньо викликає метод, спробуйте змінити все на приватне і подивіться там.
matiaslauriti

1
Що станеться, якщо дві нитки викликають привітання одночасно? Оскільки синхронізації немає, ініціалізація не буде викликана двічі (що в цьому випадку нормально, але в багатьох інших випадках не буде). Або php однопотоковий та непередбачуваний, як вузол?
Джон Маленький

53

Окрім відповіді Грега, я рекомендував би встановити конструктор приватним, щоб неможливо інстанціювати клас.

Отже, на мою скромну думку, це більш повний приклад, заснований на прикладі Грега:

<?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!


?>

1
Це чудовий підхід, але функція конструкта не може бути реалізована, якщо ваш singelton успадковує від певних об'єктів, які потребують публічного конструктора.
Ерік Герліц

4
@EricHerlitz Це питання не про одиночні, а про статичні класи. Чому ви хочете створити статичний клас, який успадковується від класу, який мав бути призначений для екземпляра?
Марк Амері

3
Рівне оголошення класу абстрактним, не дозволяючи йому бути екземпляром і все ж дозволяти викликам статичних методів.
bstoney

24

у вас можуть бути такі "статичні" схожі класи. але я припускаю, що чогось дійсно важливого не вистачає: у php у вас немає циклу додатків, тому ви не отримаєте справжнього статичного (або синглтонного) у всій своїй програмі ...

див. Singleton в PHP


1
Статичні класи та одинаки - це лише дві різні речі.
Макс Куттінс

4
final Class B{

    static $staticVar;
    static function getA(){
        self::$staticVar = New A;
    }
}

Структура b називається обробником сингетону, ви також можете це зробити в

Class a{
    static $instance;
    static function getA(...){
        if(!isset(self::$staticVar)){
            self::$staticVar = New A(...);
        }
        return self::$staticVar;
    }
}

це одне використання $a = a::getA(...);


3

Я зазвичай вважаю за краще писати звичайні нестатичні класи та використовувати заводський клас для інстанціювання одиночних (sudo статичних) екземплярів об'єкта.

Таким чином, конструктор і деструктор працюють у нормі, і я можу створювати додаткові нестатичні екземпляри, якщо хочу (наприклад, друге з'єднання БД)

Я використовую це постійно і особливо корисно для створення користувальницьких обробників сеансів зберігання БД, оскільки, коли сторінка припиняється, деструктор підштовхне сеанс до бази даних.

Ще одна перевага полягає в тому, що ви можете ігнорувати порядок дзвінка, оскільки все буде налаштовано на вимогу.

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();

1
Це насправді реалізація однотонної схеми, і її дійсно не слід використовувати - дотримуйтесь замість цього введення залежностей, яке перевіряється та полегшує налагодження.
Томас Хансен

1
Чи можете ви навести приклад того, як використовувати ін'єкцію залежності для цієї відповіді та як це робить її більш тестовою?
cjsimon

2

об'єкт неможливо визначити статично, але це працює

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();

1
Андреас Нідермайр: ось як працює php (цикл додатків = один запит) Але синглтон (для того, хто живе у запиті) - це доступність у php (у php синглтон - це об'єкт, який має 1 екземпляр (у програмі цикл)
борель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.