• Готовимся к собеседованию по PHP: ключевое слово «static. Почему некоторые PHP-разработчики предпочитают статические API? Бодрый static php p

    Reg.ru: домены и хостинг

    Крупнейший регистратор и хостинг-провайдер в России.

    Более 2 миллионов доменных имен на обслуживании.

    Продвижение, почта для домена, решения для бизнеса.

    Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

    *Наведите курсор мыши для приостановки прокрутки.

    Назад Вперед

    Статические методы и свойства в PHP

    В предыдущих материалах мы освоили основные возможности объектно-ориентированного программирования в PHP и сейчас переходим к изучению более сложных и интересных аспектов.

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

    Отсюда следовал вывод, что что в объектно-ориентированном программировании реальная работа выполняется с помощью экземпляров классов. А классы в конечном счете - это просто шаблоны для создания объектов.

    Но на самом деле не все так просто. Мы можем получать доступ и к методам, и к свойствам в контексте класса, а не объекта. Такие методы и свойства называются "статическими" и должны быть объявлены с помощью ключевого слова static .

    Class StaticExample { static public $aNum = 0; static public function sayHello() { print "Привет!"; } }

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

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

    Поскольку доступ к статическому элементу осуществляется через класс, а не через экземпляр объекта, нам не нужна переменная, которая ссылается на объект. Вместо этого используется имя класса, после которого указывается два двоеточия "::".

    Print StaticExample::$aNum; StaticExample::sayHello();

    С этим синтаксисом вы уже должны быть знакомы по основам ООП в PHP. Мы использовали конструкцию "::" в сочетании с ключевым словом parent для того, чтобы получить доступ к переопределенному методу родительского класса.

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

    Чтобы получить доступ к статическому методу или свойству из того же самого класса (а не из дочернего класса), мы будем использовать ключевое слово self .

    Ключевое слово self используется для обращения к текущему классу, а псевдопеременная $this - к текущему объекту. Поэтому из-за пределов класса StaticExample мы обращаемся к свойству $aNum с помощью имени его класса.

    StaticExample::$aNum;

    А внутри класса StaticExample можно использовать ключевое слово self .

    Class StaticExample { static public $aNum = 0; static public function sayHello() { self::$aNum++; print "Привет! (" . self::$aNum . ")\n"; } }

    Обратите внимание: кроме случаев обращения к переопределенному методу родительского класса, конструкция "::" должна всегда использоваться только для доступа к статическим методам или свойствам.

    По определению статические методы не вызываются в контексте объекта. По этой причине статические методы и свойства часто называют переменными и свойствами класса. Как следствие, нельзя использовать псевдопеременную $this внутри статического метода.

    А зачем вообще использовать статический метод или свойство?

    Вот мы и дошли до самого важного вопроса. Дело в том, что у статических элементов есть ряд полезных характеристик.

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

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

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

    Чтобы продемонстрировать это, давайте создадим статический метод для класса ShopProduct , который будет автоматически создавать экземпляры объектов ShopProduct . C помощью SQLite определим таблицу products следующим образом:

    CREATE TABLE products (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, firstname TEXT, mainname TEXT, title TEXT, price float, numpages int, playlength int, discount int)

    Теперь создадим метод getInstance() , которому передается идентификатор строки и объект типа PDO. Они будут использоваться для извлечения строки из таблицы базы данных, на основании которой затем формируется объект типа ShopProduct , возвращаемый в вызывающую программу.

    Мы можем добавить эти методы к классу ShopProduct , который был создан нам в более ранних материалах. Как вы, наверное, знаете, PDO расшифровывается как PHP Data Object (объекты данных PHP). Класс PDO обеспечивает универсальный интерфейс для различных приложений баз данных.

    // Класс ShopProduct private $id = 0; public function setID($id) { $this->id = $id; } // ... public static function getInstance($id, PDO $pdo) { $stmt = $pdo->prepare("select * from products where id=?"); $result = $stmt->execute(array($id)); $row = $stmt->fetch(); if (empty($row)) { return null; } if ($row["type"] == "book") { $product = new BookProduct($row["title"], $row["firstname"], $row["mainname"], $row["price"], $row["numpages"]); } else if ($row["type"] == "cd") { $product = new CdProduct($row["title"], $row["firstname"], $row["mainname"], $row["price"], $row["playlength"]); } else { $product = new ShopProduct($row["title"], $row["firstname"], $row["mainname"], $row["price"]); } $product->setId($row["id"]); $product->setDiscount($row["discount"]); return $product; } // ...

    Как видите, метод getInstance() возвращает объект типа ShopProduct , причем он достаточно "умен" для того, чтобы на основании значения поля type создавать объект с нужными характеристиками.

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

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

    Метод getInstance() более полезен в контексте класса, чем в контексте объекта. Он позволяет легко преобразовать данные, находящиеся в базе данных, в объект, причем для этого нам не нужно иметь отдельный экземпляр объекта типа ShopProduct .

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

    $dsn = "sqlite://home/bob/projects/products.db"; $pdo = new PDO ($dsn, null, null); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $obj = ShopProduct::getInstance(1, $pdo);

    Подобные методы работают как "фабрики", поскольку они берут "сырые" материалы (например, данные, полученные из строки базы данных или файла конфигурации) и используют их для создания объектов.

    Термин "фабрика" относится к коду, предназначенному для создания экземпляров объектов. С примерами подобных "фабрик" мы еще встретимся с вами дальше.


    Постоянные свойства

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

    Для этого можно определить постоянные свойства внутри класса. Как и глобальные константы, константы класса нельзя изменять после того, как они были определены. Постоянное свойство объявляют с помощью ключевого слова const .

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

    Class ShopProduct { const AVAILABLE = 0; const OUT_OF_STOCK = 1; // ...

    Постоянные свойства могут содержать только значения, относящиеся к элементарному типу. Константе нельзя присвоить объект.

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

    Print ShopProduct::AVAILABLE;

    Попытка присвоить константе значение после того, как она была объявлена, приведет к ошибке на этапе синтаксического анализа..

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

    На этом данную статью я завершаю, а в следующей речь пойдет про .

    Понравился материал и хотите отблагодарить?
    Просто поделитесь с друзьями и коллегами!


    (Late Static Binding, LSB) является бурно темой обсуждений последние три года в кругах разработчиков PHP (и наконец мы его получили в PHP 5.3). Но зачем оно нужно? В данной статье, как раз и будет рассматриваться, как позднее статическое связывание может значительно упростить ваш код.

    На встрече разработчиков PHP, которая проходила в Париже в ноябре 2005 года, тема позднего статического связывания официально обсуждалась основной командой разработчиков. Они согласились реализовать его, наряду со многими другими темами, которые стояли на повестке дня. Детали должны были быть согласованы в ходе открытых дискуссий.

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

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

    Class Beer { const NAME = "Beer!"; public function getName() { return self::NAME; } } class Ale extends Beer { const NAME = "Ale!"; } $beerDrink = new Beer; $aleDrink = new Ale; echo "Beer is: " . $beerDrink->getName() ."\n"; echo "Ale is: " . $aleDrink->getName() ."\n";

    Этот код выдаст такой результат:

    Beer is: Beer! Ale is: Beer!

    Класс Ale унаследовал метод getName() , но при этом self все еще указывает на класс в котором оно используется (в данном случае это класс Beer ). Это осталось и в PHP 5.3, но добавилось слово static . И снова рассмотрим пример:

    Class Beer { const NAME = "Beer!"; public function getName() { return self::NAME; } public function getStaticName() { return static::NAME; } } class Ale extends Beer { const NAME = "Ale!"; } $beerDrink = new Beer; $aleDrink = new Ale; echo "Beer is: " . $beerDrink->getName() ."\n"; echo "Ale is: " . $aleDrink->getName() ."\n"; echo "Beer is actually: " . $beerDrink->getStaticName() ."\n"; echo "Ale is actually: " . $aleDrink->getStaticName() ."\n";

    Новое ключевое слово static указывает, что необходимо использовать константу унаследованного класса, вместо константы которая была определена в классе где объявлен метод getStaticName() . Слово static было добавлено, чтобы реализовать новый функционал, а для обратной совместимости self работает также как и в предыдущих версиях PHP.

    Внутренне, основное отличие (и, собственно, причина почему связывание назвали поздним) между этими двумя способами доступа, в том, что PHP определят значение для self::NAME во время «компиляции» (когда симовлы PHP преобразуются в машинный код, который будет обрабатываться движком Zend), а для static::NAME значение будет определено в момент запуска (в тот момент, когда машинный код будет выполнятся в движке Zend).

    Это еще один инструмент для PHP-разработчиков. Во второй части рассмотрим как его можно использовать во благо.

    ". Я написал ответную статью, но так и не опубликовал ее. А вот недавно увидел нечто, что можно назвать «Классо-Ориентированное Программирование». Это освежило мой интерес к теме и вот результат.

    «Классо-Ориентированое Программирование» - это когда используются классы, состоящие только из статических методов и свойств, а экземпляр класса никогда не создается. В этой статье я буду говорить о том, что:

    • это не дает никаких преимуществ по сравнению с процедурным программированием
    • не стоит отказываться от объектов
    • наличие статических членов класса!= смерть тестам
    Хотя эта статья про PHP, концепции применимы и к другим языкам.

    Зависимости

    Обычно, код зависит от другого кода. Например:

    $foo = substr($bar, 42);
    Этот код зависит от переменной $bar и функции substr . $bar - это просто локальная переменная, определенная немного выше в этом же файле и в той же области видимости. substr - это функция ядра PHP. Здесь все просто.

    Теперь, такой пример:

    Class BloomFilter { ... public function __construct($m, $k) { ... } public static function getK($m, $n) { return ceil(($m / $n) * log(2)); } ... }
    Эта маленькая вспомогательная функция просто предоставляет обертку для конкретного алгоритма, который помогает рассчитать хорошее число для аргумета $k , используемого в конструкторе. Т.к. она должна быть вызвана до создания экземпляра класса, она должна быть статичной. Этот алгоритм не имеет внешних зависимостей и вряд ли будет заменен. Он используется так:

    $m = 10000; $n = 2000; $b = new BloomFilter($m, BloomFilter::getK($m, $n));
    Это не создает никаких дополнительных зависимостей. Класс зависит сам от себя.

  • Альтернативный конструктор. Хорошим примером является класс DateTime , встроенный в PHP. Его экземпляр можно создать двумя разными способами:

    $date = new DateTime("2012-11-04"); $date = DateTime::createFromFormat("d-m-Y", "04-11-2012");
    В обоих случая результатом будет экземпляр DateTime и в обоих случаях код привязан к классу DateTime так или иначе. Статический метод DateTime::createFromFormat - это альтернативный коструктор объекта, возвращающий тоже самое что и new DateTime , но используя дополнительную функциональность. Там, где можно написать new Class , можно написать и Class::method() . Никаких новых зависимостей при этом не возникает.

  • Остальные варианты использования статических методов влияют на связывание и могут образовывать неявные зависимости.

    Слово об абстракции

    Зачем вся эта возня с зависимостями? Возможность абстрагировать! С ростом Вашего продукта, растет его сложность. И абстракция - ключ к управлению сложностью.

    Для примера, у Вас есть класс Application , который представляет Ваше приложение. Он общается с классом User , который является предствлением пользователя. Который получает данные от Database . Классу Database нужен DatabaseDriver . DatabaseDriver нужны параметры подключения. И так далее. Если просто вызвать Application::start() статически, который вызовет User::getData() статически, который вызовет БД статически и так далее, в надежде, что каждый слой разберется со своими зависимостями, можно получить ужасный бардак, если что-то пойдет не так. Невозможно угадать, будет ли работать вызов Application::start() , потому что совсем не очевидно, как себя поведут внутренние зависимости. Еще хуже то, что единственный способ влиять на поведение Application::start() - это изменять исходный код этого класса и код классов которые он вызызвает и код классов, которые вызызвают те классы… в доме который построил Джек.

    Наиболее эффективный подход, при создании сложных приложений - это создание отдельных частей, на которые можно опираться в дальнейшем. Частей, о которых можно перестать думать, в которых можно быть уверенным. Например, при вызове статического Database::fetchAll(...) , нет никаких гарантий, что соединение с БД уже установлено или будет установлено.

    Function (Database $database) { ... }
    Если код внутри этой функции будет выполнен - это значит, что экземпляр Database был успешно передан, что значит, что экземпляр объекта Database был успешно создан. Если класс Database спроектирован верно, то можно быть уверенным, что наличие экземпляра этого класса означает возможность выполнять запросы к БД. Если экземпляра класса не будет, то тело функции не будет выполнено. Это значит, что функция не должна заботиться о состоянии БД, класс Database это сделает сам. Такой подход позволяет забыть о зависимостях и сконцентрироваться на решении задач.

    Без возможности не думать о зависимостях и зависимостях этих зависимостей, практически невозможно написать хоть сколь-нибудь сложное приложение. Database может быть маленьким классом-оберткой или гигантским многослойным монстром с кучей зависимостей, он может начаться как маленькая обертка и мутировать в гигантского монстра со временем, Вы можете унаследовать класс Database и передать в функцию потомок, это все не важно для Вашей function (Database $database) , до тех пор пока, публичный интерфейс Database не изменяется. Если Ваши классы правильно отделены от остальных частей приложения с помощью внедрения зависимостей, Вы можете тестировать каждый из них, используя заглушки вместо их зависимостей. Когда Вы протестировали класс достаточно, чтобы убедиться, что он работает как надо, Вы можете выкинуть лишнее из головы, просто зная, что для работы с БД нужно использовать экземпляр Database .

    Классо-ориентированное программирование - глупость. Учитесь использовать ООП.

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

    Если говорить более точно, позднее статическое связывание сохраняет имя класса указанного в последнем "не перенаправленном вызове". В случае статических вызовов это явно указанный класс (обычно слева от оператора :: ); в случае не статических вызовов это класс объекта. "Перенаправленный вызов" - это статический вызов, начинающийся с self:: , parent:: , static:: , или, если двигаться вверх по иерархии классов, forward_static_call() . Функция get_called_class() может быть использована чтобы получить строку с именем вызванного класса, и static:: представляет ее область действия.

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

    Ограничения self::

    Пример #1 Использование self::

    class A {
    echo __CLASS__ ;
    }
    public static function
    test () {
    self :: who ();
    }
    }

    class B extends A {
    public static function who () {
    echo __CLASS__ ;
    }
    }

    B :: test ();
    ?>

    Использование позднего статического связывания

    Позднее статическое связывание пытается устранить это ограничение предоставляя ключевое слово, которое ссылается на класс, вызванный непосредственно в ходе выполнения. Попросту говоря, ключевое слово, которое позволит вам ссылаться на B из test() в предыдущем примере. Было решено не вводить новое ключевое слово, а использовать static , которое уже зарезервировано.

    Пример #2 Простое использованиеstatic::

    class A {
    public static function who () {
    echo __CLASS__ ;
    }
    public static function
    test () {
    static:: who (); // Здесь действует позднее статическое связывание
    }
    }

    class B extends A {
    public static function who () {
    echo __CLASS__ ;
    }
    }

    B :: test ();
    ?>

    Результат выполнения данного примера:

    Замечание :

    В нестатическом контексте вызванным классом будет тот, к которому относится экземпляр объекта. Поскольку $this-> будет пытаться вызывать закрытые методы из той же области действия, использование static:: может дать разные результаты. Другое отличие в том, что static:: может ссылаться только на статические поля класса.

    Пример #3 Использование static:: в нестатическом контексте

    class A {
    private function foo () {
    echo "success!\n" ;
    }
    public function test () {
    $this -> foo ();
    static:: foo ();
    }
    }

    class B extends A {
    /* foo() будет скопирован в В, следовательно его область действия по прежнему А,
    и вызов будет успешен*/
    }

    class C extends A {
    private function foo () {
    /* исходный метод заменен; область действия нового метода С */
    }
    }

    $b = new B ();
    $b -> test ();
    $c = new C ();
    $c -> test (); //не верно
    ?>

    Результат выполнения данного примера:

    success! success! success! Fatal error: Call to private method C::foo() from context "A" in /tmp/test.php on line 9

    Замечание :

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

    Пример #4 Перенаправленные и не перенаправленные вызовы

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

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

    На примере станет сразу понятно. Давайте создадим обект Math (сокращённое названием математики в английском).

    Статические методы PHP
    "; $math_1 = new Math(); $math_2 = new Math(); $math_3 = new Math(); $math_4 = new Math(); echo "Создано объектов: " . Math::getCount(); ?>

    Этот класс предоставляет инструменты для работы с математическими функциями без необходимости создания объекта. В классе есть конструктор, который увеличивает статическое свойство $count на единицу. Класс запоминает значение этого свойства, так как оно статическое.

    Кстати, для объявления метода или свойства статическим используется слово static , а для доступа к статическому свойству используется слово self с двойным двоеточием " :: ".

    Всё это лучше понять в сравнении, особенно в сравнении рабочего примера с ошибочным. Давайте немного расширим наш пример.

    Статические методы PHP counter++; } public static function calcSin($x) { return sin($x); } public static function calcSQRT($x) { return sqrt($x); } public static function getCount() { return self::$count; } public function getCounter() { return $this->counter; } } echo Math::calcSin(1); echo "
    "; echo Math::calcSQRT(9); echo "
    "; $math_1 = new Math(); $math_2 = new Math(); $math_3 = new Math(); $math_4 = new Math(); echo "Создано объектов: " . Math::getCount(); echo "
    "; echo "Создано объектов: " . $math_4->getCounter(); ?>

    В этом примере мы добавили классу обычное свойство $counter , оно также увеличивалось на единицу в конструкторе. Но обычное свойство принадлежит объекту, поэтому оно не сохраняется между вызовами объектов. При любом создании экземпляра класса (объекта) свойство будет равно нолю, в конструкторе оно будет увеличено на единицу.

    Статическое свойство принадлежит классу, поэтому его значение сохраняется.

    Ниже ещё несколько примеров, которые раскрывают работу статических свойств и методов.

    Попытка использовать в статическом методе переменную $this приведёт к ошибке (Fatal error: Using $this when not in object context).

    Статические методы PHP age . " old."; // это ошибка "Using $this when not in object context". } } $TestClass = new TestClass(); $TestClass->sayHello(); ?>

    Кстати, без строки:

    $TestClass->sayHello();

    ошибки не будет, но как только вы в коде попробуете запустить статический метод с переменной $this , вы сразу получите сообщение об ошибке.

    Если в этом примере убрать слово static , то ошибки не будет.

    Если из статического метода обратиться к свойству объекта, то это приведёт к ошибке. Можно обращаться только к статическим свойствам при помощи конструкции self::$age . Обратите внимание, что тут есть знак $ перед именем переменной, в отличии от конструкции $this->age .

    Статические методы PHP sayHello(); ?>

    Если в этом примере убрать слово static перед именем свойства, то возникнет ошибка "Access to undeclared static property".

    Статические свойства отсутствуют в объектах класса.

    Статические методы PHP "; print_r($TestClass); echo ""; ?>

    Статический метод можно вызвать используя конструкцию self::метод() . Пример:

    Статические методы PHP printHello(); ?>

    Статическое свойство можно получить в контексте класса используя синтаксис:

    echo TestClass::$age;

    Причём попытка обращения к обычному свойству таким образом приведёт к ошибке: "Fatal error: Access to undeclared static property".

    Статическое свойство можно менять в контексте класса используя синтаксис:

    TestClass::$age += 20; // например

    Ещё пример кода со статическими методами и свойствами

    В этом примере ещё простые варианты использования статических методов и свойств. Чем больше простого кода вы поймёте, тем лучше запомните материал.

    Статические методы PHP ".TestClass::$age; // echo TestClass::$txt; // Ошибка: Fatal error: Access to undeclared static property. echo "
    "; TestClass::sayHi(); echo "
    "; TestClass::sayHello(); // А вот так у меня получилось получить доступ к статической переменной через объект ($obj::$age)... echo "
    "; $obj = new TestClass; echo "Получаем поступ к статической переменной через объект: " . $obj::$age; ?>

    Обратите внимание, и это важно, в этом примере мы обратились к нестатическому методу sayHi() используя синтаксис обращения к статическим элементам класса.

    Резюме

    • Главное: статические свойства принадлежат классам, а не объектам.
    • Из статического метода нельзя обратиться к обычным свойствам и методам класса, $this->name не работает тут.
    • Из статического метода можно обратиться к статическим свойствам используя self::$name .
    • Статические свойства класса не доступны объектам.
    • Обычный метод может обратиться к статическому свойству используя self::$name .
    • Статическое свойство можно получить в контексте класса использую синтаксис: TestClass::$age .
    • Обычный метод можно вызвать в контексте и объекта ($object->метод()), и класса используя синтаксис TestClass::метод() .
    • При помощи синтаксиса $object::$age у меня получилось получить доступ к статическому свойству через объект.

    Параллели с JavaScript

    В JavaScript есть такой класс Math, содержащий очень много различных математических функций.

    Для проведения математических вычислений (расчёт синуса или экспоненты) в JavaScript не нужно создавать обект класса Math, так как его методы являются статическими. До изучения PHP я никак не мог понять что это такое, и только изучив классы и объекты в PHP у меня в голове всё встало на свои полочки.

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