Объект со статическими свойствами и методами

Вы уже знаете, что статические свойства и методы можно использовать, не создавая объект класса. На самом деле, однако, класс может содержать как статические свойства и методы, так и обычные.

Давайте посмотрим, как с этим работать и какие преимущества это дает. Пусть у нас есть класс Test одновременно и со статическим свойством, и с обычным:

<?php class Test { public static $staticProperty; // публичное статическое свойство public $usualProperty; // обычное свойство } ?>

Давайте, к примеру, поработаем с его обычным свойством:

<?php $test = new Test; // создаем объект класса $test->usualProperty = 'usual'; // записываем значение echo $test->usualProperty; // выведет 'usual' ?>

А теперь используем статическое свойство, не создавая объект этого класса:

<?php Test::$staticProperty = 'static'; // записываем значение echo Test::$staticProperty; // выведет 'static' ?>

На самом деле, если у нас есть переменная с объектом класса, то у этой переменной также будет доступно статическое свойство:

<?php $test = new Test; // создаем объект класса $test::$staticProperty = 'static'; // записываем значение echo $test::$staticProperty; // выведет 'static' ?>

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

<?php // Записываем значение еще ДО создания объекта: Test::$staticProperty = 'static'; // Cоздаем объект класса: $test = new Test; // Выводим статическое свойство: echo $test::$staticProperty; // выведет 'static' ?>

Вот еще пример:

<?php // Cоздаем объект класса: $test = new Test; // Записываем значение в статическое свойство: $test::$staticProperty = 'static'; // Выводим значение, обратившись к классу: echo Test::$staticProperty; // выведет 'static' // Выводим значение, обратившись к объекту класса: echo $test::$staticProperty; // выведет 'static' ?>

Несколько объектов

Статические свойства принадлежат не какому-то объекту класса, а самому классу, хотя объекты класса и имеют доступ к этим свойствам.

На практике это означает то, что если у нас есть несколько объектов класса - статические свойства у них будут общие. То есть, если в одном объекте поменять значение статического свойства - изменения произойдут во всех объектах.

Давайте посмотрим на примере:

<?php $test1 = new Test; // первый объект $test2 = new Test; // второй объект $test1::$staticProperty = 'static'; // запишем значение, используя первый объект echo $test1::$staticProperty; // выведет 'static' echo $test2::$staticProperty; //!! также выведет 'static' ?>

Статические методы и $this

Пусть у нас есть класс Test с двумя свойствами, статическим и обычным:

<?php class Test { public static $staticProperty = 'static'; // статическое свойство public $usualProperty = 'usual'; // обычное свойство } ?>

Давайте выведем значения этих свойств в обычном (нестатическом) методе method:

<?php class Test { public static $staticProperty = 'static'; // статическое свойство public $usualProperty = 'usual'; // обычное свойство // Обычный метод: public function method() { var_dump(self::$staticProperty); // выведет 'static' var_dump($this->usualProperty); // выведет 'usual' } } $test = new Test; $test->method(); // обычный метод - вызываем через -> ?>

Из примера видно, что в обычном методе доступны как статические, так и обычные свойства (и методы).

Пусть теперь наш метод method будет статическим. В этом случае он сможет обратиться с статическим методом и свойствам, но к обычным - нет.

Почему: потому что внутри статических методов недоступен $this. Это происходит из-за того, что статические методы могут вызываться вне контекста объекта, просто обращаясь к имени класса.

А ведь $this внутри класса как раз-таки ссылается на объект этого класса. Нет объекта - $this ни на что не ссылается.

Убедимся в этом: переделаем наш метод на статический - теперь обращение к обычному свойству внутри нашего метода будет выдавать ошибку:

<?php class Test { public static $staticProperty = 'static'; // статическое свойство public $usualProperty = 'usual'; // обычное свойство //!! Переделали на статический метод: public static function method() { var_dump(self::$staticProperty); // выведет 'static' var_dump($this->usualProperty); //!! выдаст ошибку } } $test = new Test; $test::method(); // статический метод - вызываем через :: ?>

Применение

Пусть у нас есть вот такой класс User:

<?php class User { public $name; public function __construct($name) { $this->name = $name; } } ?>

Давайте сделаем так, чтобы этот класс подсчитывал количество своих объектов.

Для этого сделаем статическое свойство count. Изначально запишем в него значение 0, а при создании каждого нового объекта будем увеличивать это значение на 1.

Будем увеличивать значение нашего счетчика в конструкторе объекта:

<?php class User { public static $count = 0; // счетчик объектов public $name; public function __construct($name) { $this->name = $name; // Увеличиваем счетчик при создании объекта: self::$count++; } } ?>

Проверим, что все работает:

<?php $user1 = new User('user1'); // создаем первый объект класса echo User::$count; //выведет 1 $user2 = new User('user2'); // создаем второй объект класса echo User::$count; //выведет 2 ?>

Не подсматривая в мой код реализуйте такой же класс User, подсчитывающий количество своих объектов.

Улучшим наш код

Не очень хорошо то, что наш счетчик публичный - его случайно можно изменить снаружи класса.

Давайте сделаем его доступным только для чтения. Для этого объявим его приватным и сделаем для него статический метод-геттер getCount:

<?php class User { private static $count = 0; public $name; public function __construct($name) { $this->name = $name; // Увеличиваем счетчик при создании объекта: self::$count++; } // Метод, возвращающий значение счетчика: public static function getCount() { // Выводим значение счетчика: return self::$count; } } ?>

Проверим:

<?php $user1 = new User('user1'); // создаем первый объект класса echo User::getCount(); //выведет 1 $user2 = new User('user2'); // создаем второй объект класса echo User::getCount(); //выведет 2 ?>

Самостоятельно переделайте код вашего класса User в соответствии с теоретической частью урока.