Статические методы и свойства в PHP
Сегодня мы поговорим о статических свойствах и методах в PHP. Если коротко – то это свойства и методы, которые принадлежат классу целиком, а не созданным объектам этого класса. То есть использовать их можно даже без создания объектов. Иногда их называют просто свойствами и методами класса. Не путайте их со свойствами и методами объектов, которые мы изучали ранее!
Продолжение урока будет доступно вам
после покупки ООП в PHP
Когда использовать статические методы
В обсуждениях к посту (перевод) о именованных конструкторах прозвучало мнение, что статические методы плохи и их вообще не стоит использовать. На мой взгляд, это слишком большое обобщение.
Статические методы по сути своей просто способ организации глобальных функций в пространства имен. Использование пространств имен, я думаю, вы согласитесь — хороший тон. Что касается глобальных функций — мы используем их всегда, встроенные функции PHP составляют основу нашего кода.
Основная проблема здесь — отсутствие совместно используемого глобального состояния. Вот пример из прошлого поста:
В данном примере возвращаемый результат свободен от побочных эффектов и вполне предсказуем, т.к. зависит только от аргументов, подаваемых на вход. Каждый раз при вызове метода вам будет возвращен идентичный результат (объект Time со значением 11:45), вне зависимости от состояния системы, контекста или чего-либо еще.
Другой пример:
И снова — результат предсказуем, Calculator::sum(1, 2); предоставляет нам сервис, не имеющий состояния, и не зависящий ни от чего, кроме аргументов. Более того, эта реализация не может быть полиморфной или иметь различные имплементации, т.к. любой результат кроме 3 будет ошибкой. Да, вы можете изменить внутреннюю реализацию метода, улучшив алгоритм сложения чисел, но это не должно никак отражаться на результате его использования.
Возьмем обратный пример, на этот раз с состоянием:
Пример элементарный, но в более сложных ситуациях это может быть не столь доходчиво. Представьте, что два разработчика используют в своем коде счетчики. Когда они тестируют свое решение изолированно — нет никаких проблем. Но после интеграции их решений счетчик начинает работать не так, как ожидалось, потому что используется глобальное состояние, вместо того, чтобы воспользоваться отдельным экземпляром счетчика.
Абстракция
Возможно, вы все еще чувствуете неприятие против кода, вроде Calculator::sum($x, $y) , т.к. мы не можем сымитировать или расширить его. Но не стоит забывать, что это довольно низкий уровень абстракции. Вы также не сможете сымитировать и расширить оператор + в PHP, но я не думаю, что вы когда-либо чувствовали потребность в этом. Если вам нужен более высокий уровень абстракции, то композиция — ваш верный спутник. Но хочу заметить, между Calculator::sum($x, $y) и + есть довольно интересное различие, первый может вот так, а второй нет:
Это все может показаться избыточным, но не стоит забывать про функции и статические методы, ведь они могут быть очень полезны при правильном их применении.
Часть 1: Как использовать именованные конструкторы в PHP
- Веб-разработка
- PHP
- Программирование
Статические методы — PHP: Введение в ООП
Статические методы — это почти то же самое, что и статические свойства, только методы.
class User private static $table = 'users'; public static function getTable() return self::$table; > > User::getTable(); // users
Статические методы, как и свойства, не принадлежат объектам, они — часть класса. Следовательно, из статического метода невозможно получить доступ к объекту (ведь нет никакого объекта) через $this . Внутри него $this просто не существует. Статические методы могут обращаться к другим статическим методам, статическим свойствам или константам, используя self .
Как я уже упоминал в предыдущем уроке, статические методы часто используют для доступа к приватным статическим свойствам. Причём, как геттеры, так и сеттеры, которые нужны редко, но все же бывают нужны.
Но есть ещё один способ использования статических методов, не связанный со статическими свойствами. Их используют как способ создать объект вместо прямого вызова конструктора через оператор new .
Как вы помните, PHP (как, впрочем, и любой динамический язык) позволяет иметь ровно один конструктор для класса. В случае таких данных, как время, это — серьёзное ограничение, потому, что нельзя одним конструктором описать все возможные способы создания дат, которые используются в коде.
$date = new DateTime('2000-01-01');
В стандартной библиотеке PHP есть класс DateTime , который принимает на вход строчку определённого формата и возвращает соответствующий объект. А что, если в нашей программе формат времени другой? А если у нас вообще нет строчки, а есть отдельные числа? Естественным желанием было бы иметь разные конструкторы под разные задачи. Их у нас нет, но зато есть статические методы, которых можно создать столько, сколько нужно.
// Специальная библиотека для работы с датами будет рассматриваться в следующем курсе $vancouverTimeRightNow = Carbon::now('America/Vancouver'); //implicit __toString() $noonTodayLondonTime = Carbon::createFromTime(12, 0, 0, 'Europe/London'); $internetWillBlowUpOn = Carbon::create(2038, 01, 19, 3, 14, 7, 'GMT');
Как видно из кода выше, статические методы имеют разные сигнатуры, но внутри они, так или иначе, вызывают конструктор, передавая туда уже подготовленные параметры. Конструктор можно вызывать двумя способами: первый — использовать полное имя класса, второй — через self . Второй способ предпочтительнее просто потому, что позволяет не дублировать имя класса.
class Carbon public static function now($timezone = '') return new self(date("Y-m-d H:i:s"), $timezone); > >
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Зачем нужны статические методы php
Reg.ru: домены и хостинг
Крупнейший регистратор и хостинг-провайдер в России.
Более 2 миллионов доменных имен на обслуживании.
Продвижение, почта для домена, решения для бизнеса.
Более 700 тыс. клиентов по всему миру уже сделали свой выбор.
Бесплатный Курс «Практика HTML5 и CSS3»
Освойте бесплатно пошаговый видеокурс
по основам адаптивной верстки
на HTML5 и CSS3 с полного нуля.
Фреймворк Bootstrap: быстрая адаптивная вёрстка
Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.
Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.
Верстайте на заказ и получайте деньги.
Бесплатный тренинг «PHP для Создания Сайтов: Введение»
Что нужно знать для создания PHP-сайтов?
Ответ здесь. Только самое важное и полезное для начинающего веб-разработчика.
Узнайте, как создавать качественные сайты на PHP всего за 2 часа и 27 минут!
—> Бесплатный курс «Сайт-Визитка За 15 уроков»
Создайте свой сайт за 3 часа и 30 минут.
После просмотра данного видеокурса у Вас на компьютере будет готовый к использованию сайт, который Вы сделали сами.
Вам останется лишь наполнить его нужной информацией и изменить дизайн (по желанию).
—> Бесплатный курс «Основы HTML и CSS»
Изучите основы HTML и CSS менее чем за 4 часа.
После просмотра данного видеокурса Вы перестанете с ужасом смотреть на HTML-код и будете понимать, как он работает.
Вы сможете создать свои первые HTML-страницы и придать им нужный вид с помощью CSS.
Бесплатный курс «Сайт на WordPress»
Хотите освоить CMS WordPress?
Получите уроки по дизайну и верстке сайта на WordPress.
Научитесь работать с темами и нарезать макет.
Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!
Бесплатный курс «Основы работы с JavaScript»
Хотите изучить JavaScript, но не знаете, как подступиться?
После прохождения видеокурса Вы освоите базовые моменты работы с JavaScript.
Развеются мифы о сложности работы с этим языком, и Вы будете готовы изучать JavaScript на более серьезном уровне.
*Наведите курсор мыши для приостановки прокрутки.
Статические методы и свойства в PHP
Перед изучением данной статьи вы можете прочитать предыдущую статью из этой серии — «Управление доступом к классам: спецификаторы доступа public, private и protected».
В предыдущих материалах мы освоили основные возможности объектно-ориентированного программирования в 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 = $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;
Попытка присвоить константе значение после того, как она была объявлена, приведет к ошибке на этапе синтаксического анализа..
Константы следует использовать, когда свойство должно быть доступным для всех экземпляров класса и когда значение свойства должно быть фиксированным и неизменным.
На этом данную статью я завершаю, а в следующей речь пойдет про абстрактные классы и интерфейсы в PHP.
Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!
Смотрите также:










Поиск по сайту
Фреймворк Yii2: первая практика

Овладейте начальными знаниями и навыками по работе в фреймворке Yii2, которые необходимы любому веб-разработчику!
Дизайн лендинга

Создавайте дизайн любых сайтов - для себя и на заказ!
В Гармонии с Кодом
Если вы хотите создать сайт своими руками, то вы оказались в нужном месте. Здесь вы найдете обучающие видеокурсы, а также множество видеоуроков и статей по веб-разработке и созданию сайтов.
Уважаемый веб-мастер! В создание данного ресурса вложено много сил и времени. Буду рад, если при копировании материалов вы будете ставить активную ссылку на Codeharmony.ru.
