Хорошо использовать статическую переменную внутри метода класса PHP

Я делаю класс «Контейнер» для хранения всех экземпляров моей модели/сервиса, класс является одноэлементным.

Рассмотрим следующую часть кода (из проекта CodeIgniter):

public function getReviewModel()
{
    static $loaded = false;

    if (!$loaded)
    {
        $this->load->model('review_model');

        $loaded = true;
    }

    return $this->review_model;
}

Мне интересно, можно ли по-прежнему использовать статический внутренний метод, подобный этому, или мне следует использовать только свойство класса (я имею в виду стандарт производительности и кодирования)?


person Thomas Decaux    schedule 03.02.2014    source источник


Ответы (2)


Общее мнение относительно статики в PHP таково: Избегайте, если это вообще возможно. И да, в 99% случаев можно избежать статики.
Синглтонов следует избегать в 100% случаев. По причинам, которые вы можете найти здесь и практически везде в Интернете. Синглтоны похожи на коммунизм: звучит как хорошая идея, но когда ее реализуют на практике, оказывается, что есть одна или две вещи, которых вы не ожидали.
Основная цель синглтона — сохранять состояние, но сам PHP не имеет состояния. , так что приходит следующий запрос, синглтон все равно нужно повторно инициализировать.

Если я пишу геттеры, подобные вашим, я склонен создавать их с ленивой загрузкой:

class Example
{
    private $reviewModel = null;//create property
    public function getReviewModel()
    {
        if ($this->reviewModel === null)
        {//load once the method is called, the first time
            $this->reviewModel = $this->load->model('review_model');
        }
        return $this->reviewModel;
    }
}

Это в основном делает то же самое, без использования статики. Поскольку я использую свойство, я по-прежнему сохраняю экземпляр, поэтому, если метод getReviewModel вызывается снова, вызов load->model пропускается, как и при использовании статического метода.
Однако, поскольку вы спрашиваете о производительности а также стандарты кодирования: статика немного медленнее, чем свойства экземпляра: у каждого экземпляра есть HashTable, содержащая его свойства, и указатель на его определение. Статические свойства находятся в последнем, поскольку они являются общими для всех экземпляров, поэтому статическое свойство требует дополнительной работы по поиску:

instance -> HashTable -> property
instance -> definition -> HashTable -> property

Это не полная история, проверьте ответ + ссылки здесь, но в основном: путь к статическому свойству длиннее.

Что касается стандартов кодирования: они существуют, хотя пока еще неофициальны, большинство крупных игроков подписываются на них, и вам следует: PHP -FIG
Такие вещи, как $this->_protectedProperty;, например, не соответствуют стандарту PSR-2, в котором совершенно недвусмысленно говорится:

Имена свойств НЕ ДОЛЖНЫ иметь префикс с одним подчеркиванием, чтобы указать защищенную или частную видимость.

person Elias Van Ootegem    schedule 03.02.2014
comment
Где вы видите, что мы должны избегать статики внутри метода? На самом деле я ищу информацию, потому что я всегда думал, что это лучше (в данном конкретном случае), чем создавать свойства класса X, спасибо. - person Thomas Decaux; 03.02.2014
comment
@ThomasDecaux: почему синглтоны плохи и почему статика в PHP практически не имеет смысла, много раз обсуждалось на этом сайте , но вот хороший пример одного из ответов. По сути: статика — это глобальные перетаскивания, которые препятствуют тестированию прежде всего. PHP, по сути, является средой выполнения без сохранения состояния. Зачем же тогда использовать паттерн, полностью посвященный сохранению состояния? Просто взгляните на следующие три слова, которые не соответствуют двум другим: Stateles, OO и static (имейте в виду, что static также доступен по всему миру). - person Elias Van Ootegem; 03.02.2014
comment
Извините, когда я имею в виду синглтон, я имею в виду один экземпляр контейнера, а не шаблон синглтона. Я просто хочу знать, есть ли веская причина использовать свойство класса вместо статической переменной в методах класса. - person Thomas Decaux; 03.02.2014
comment
Спасибо за объяснение управления памятью, очень подробно. Но если я храню 100 свойств частного класса, которые никогда не устанавливаются, занимает ли это память? - person Thomas Decaux; 03.02.2014
comment
@ThomasDecaux: Да: свойство немного более производительно, упрощает тестирование вашего кода и делает его более пригодным для повторного использования, статический код не масштабируется, его сложнее тестировать и он не имеет смысла в PHP. Если вам нужен доступ к свойству, использование статических вызовов — просто уродливое быстрое решение. - person Elias Van Ootegem; 03.02.2014
comment
@ThomasDecaux: В некотором смысле да: в зависимости от вашей системы требуется что-нибудь в диапазоне от 800 байт до 1,6 КБ в памяти (1 свойство => 1 смещение в HashTable + 1 указатель zval ... не о чем беспокоиться, или даже другие вещи занимают в 10 раз больше памяти, к тому же эта память выделяется/освобождается вместе с вашим инстансом.Статика распределяется глобально, так что оставайтесь в памяти дольше - person Elias Van Ootegem; 03.02.2014
comment
Хорошо ! Это звучит очень хороший ответ, спасибо, что уделил мне некоторое время. Где я могу найти хороший ресурс о PHP и памяти? Я буду использовать подконтейнеры, чтобы разделить мой большой контейнер. - person Thomas Decaux; 03.02.2014
comment
@ThomasDecaux: Что ж, если вы хотите узнать о внутреннем устройстве PHP, вы можете просмотреть исходный код (если вы хорошо владеете C) или использовать phpinternals - person Elias Van Ootegem; 03.02.2014
comment
Голосую за это, так как я действительно не понимаю, как в этом случае static var может быть плохим для тестов. По сути, это внутренняя часть метода! Он ИСПОЛЬЗУЕТСЯ для сохранения состояния — запросы могут не иметь состояния, но в запросе у вас наверняка могут быть потребности в состоянии. Кроме того, предлагаемое вами свойство экземпляра (даже если оно закрытое) просто раскрывает внутренности этого метода снаружи и может вызвать путаницу у разработчиков — когда я должен использовать свойство и когда я должен использовать метод?. Статическая переменная внутри метода стирает проблему, сохраняя быстрое состояние, используя ранее сгенерированные значения. - person igorsantos07; 21.02.2019

В вашем примере ничто не мешает программисту создать экземпляр класса более одного раза (с ужасными результатами), поэтому это довольно запутанный фрагмент кода.

Статические переменные имеют свое применение, независимо от того, являются ли они локальными для функции или определены на уровне класса.
Особенно в PHP-скриптах, когда вывод часто представляет собой один фрагмент данных, который можно удобно обрабатывать как класс, определяющий только статические свойства и методы. .
Это был бы настоящий, надежный одноэлементный класс.

Так как спутать статическую переменную с динамической является распространенной ошибкой, я предпочитаю статические переменные класса, чтобы избежать путаницы (т. е. синтаксис self::$... выделяет их четко).

person kuroi neko    schedule 03.02.2014
comment
Да, прости. Я имел в виду, что этот код сбивает с толку, так как он очень похож на класс. - person kuroi neko; 03.02.2014