Сигнатура метода

Самый распространенный вариант использования ключевого слова static — статический метод. Несмотря на то, что к статическим методам можно обращаться с помощью объектного оператора (->), рекомендуется использовать оператор разрешения области видимости (::), поскольку альтернатива устарела и, вероятно, будет удалена в будущем. С помощью оператора разрешения области видимости можно вызывать статические методы напрямую в классе, а не в его экземпляре. В результате этого ключевое слово $this становится недоступным в теле статических методов.

Статические методы можно использовать для реализации шаблона фабричный метод (Factory Method), который создает новые экземпляры содержащего его класса при каждом вызове. В данном примере фабричный метод fromArray создает экземпляр объекта User, присваивает ему значения из массива и возвращает экземпляр:

class User
{
    public static function fromArray($attributes)
    {
        $user = new User();
        $user->name = $attributes['first'] . ' ' . $attributes['last'];
        $user->password = password_hash($attributes['password'], PASSWORD_BCRYPT);

        return $user;
    }
}

$user = User::fromArray([
    'first' => 'ryan',
    'last' => 'cco',
    'password' => 'password'
]);

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

class UserFactory
{
    public static function build($attributes)
    {
        //
    }
}

$user = UserFactory::build($attributes);

Свойства

В отличие от обычных свойств, изменение значения статического свойства во время выполнения программы повлияет на все экземпляры содержащего свойство класса. Даже на те, для которых еще не созданы экземпляры. Таким образом, статические свойства можно рассматривать в качестве «констант изменяемого класса». На статические свойства можно ссылаться только с помощью оператора разрешения области видимости.

Благодаря природе статических свойств их можно использовать для реализации шаблона одиночка (Singleton). Одиночка содержит один и тот же экземпляр класса на протяжении всего выполнения программы.

В данном примере первый вызов Queue::getInstance() создает и назначает экземпляр Queue для Queue::$instance и возвращает его. Каждый последующий вызов будет возвращать один и тот же экземпляр Queue, ранее присвоенный Queue::$instance:

class Queue
{
    private static $instance;

    public static function getInstance()
    {
        if (static::$instance === null) {
            static::$instance = new Queue();
        }

        return static::$instance;
    }
}

Переменные

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

Статические переменные часто используются в технике оптимизации под названием мемоизация. Ее целью является ускорение дорогостоящей операции за счет кэширования результатов и сохранения их для последующего вызова с теми же параметрами.

В данном примере мы создаем уникальный для предоставленных параметров хеш и используем его для уникальной идентификации вызова в качестве ключа. Если значение $key в качестве индекса для $cache не найдено, то выполняем preg_replace и сохраняем его вывод в индексе $key, принадлежащему $cache. Каждый последующий вызов для replace с теми же параметрами будет обходить вызов preg_replace и возвращать значение из предыдущего вызова:

function replace($pattern, $replacement, $subject)
{
    static $cache = [];

    $key = md5(serialize(func_get_args()));

    if (!isset($cache[$key])) {
        $cache[$key] = preg_replace(
            $pattern, $replacement, $subject
        );
    }

    return $cache[$key];
}

Анонимные функции

Подобно методам, при определении в контексте класса анонимные функции не связаны с содержащим их классом и не имеют доступа через $this.

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

$unpublished = array_filter($posts, static function ($post) {
    return ! $post->published;
});

Позднее статическое связывание

Позднее статическое связывание демонстрирует другой вариант использования ключевого слова static: в контексте наследования. В этом контексте static относится к вызываемому классу, а не к тому, для которого был определен метод: на него, в свою очередь, будет ссылаться self или __CLASS__:

class A
{
    public function saySelfValue()
    {
        echo self::class;
    }

    public function sayClassValue()
    {
        echo __CLASS__;
    }

    public function sayStaticValue()
    {
        echo static::class;
    }
}

class B extends A
{

}

$a = new A();
$a->saySelfValue(); // 'A'
$a->sayStaticValue(); // 'A'
$a->sayStaticValue(); // 'A'

$b = new B();
$b->saySelfValue(); // 'A'
$b->sayStaticValue(); // 'B'
$b->sayStaticValue(); // 'A'

Заключение

Мы рассмотрели несколько примеров использования ключевого слова static в PHP. Хотя сценарии использования умозрительны, они очень реалистичны. Польза, которую они могут принести вашему коду, может быть огромной. По крайней мере, знакомство с этими способами использования static сделает вас сильным разработчиком.

Читайте также:


Перевод статьи Ryan Colson: The Power Of Static

Предыдущая статьяШаблон Repository в Android
Следующая статьяОсновы JavaScript: управление DOM элементами (часть 4)