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

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

Давайте посмотрим, как с этим работать и какие преимущества это дает. Пусть у нас есть класс `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` в соответствии с теоретической частью урока.

←→
↑