Основыclass
Каждое определение класса начинается с ключевого слова class, затем
идёт имя класса, а потом пара фигурных скобок, в которых определяют
свойства и методы класса.
Для класса разрешается выбирать произвольное название, при условии,
что это не зарезервированное слово языка PHP.
Начиная с PHP 8.4.0 объявление названия класса, которое состоит из одного символа подчёркивания _,
устарело.
Допустимое название класса начинается с буквы или подчеркивания,
за которым идёт произвольное количество букв, цифр или символов подчеркивания.
В виде регулярного выражения правило именования классов выглядят так:
^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.
Классы содержат константы,
переменные, которые в классах
называют свойствами, и функции, которые в классах называют методами.
Простое определение класса
var;
}
}
?>
]]>
Псевдопеременная $this доступна,
когда метод вызывается из контекста объекта.
Переменная $this — значение вызывающего объекта.
Вызов нестатического метода статически выбрасывает исключение Error.
До PHP 8.0.0 это приводило к уведомлению об устаревании,
а переменная $this оставалась неопределённой.
Примеры псевдопеременной $this
foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
]]>
&example.outputs.7;
&example.outputs.8;
Классы только для чтения
Начиная с PHP 8.2.0 класс можно пометить
модификатором readonly.
Пометка класса как readonly добавит
модификатор readonly
к каждому объявленному свойству и не разрешит создавать
динамические свойства.
Поддержку динамических свойств невозможно добавить даже атрибутом
AllowDynamicProperties. Попытка это сделать вызовет ошибку компиляции.
]]>
В классах только для чтения нельзя объявлять нетипизированные и статические свойства,
поскольку такие свойства нельзя помечать модификатором readonly:
]]>
]]>
Класс readonly получится
расширить
тогда и только тогда, когда дочерний класс
тоже readonly-класс.
Ключевое слово new
Экземпляр класса создаётся директивой new.
Новый объект создаётся, если только
конструктор объекта
во время ошибки не выбрасывает исключение.
Класс рекомендуют определять перед тем, как создавать экземпляр класса;
иногда это обязательное требование.
PHP создаст новый экземпляр класса, если с ключевым словом
new указали переменную, которая содержит строку (string)
с названием класса.
Чтобы создать экземпляр класса, который определили в пространстве имён,
требуется указывать абсолютное имя класса.
Круглые скобки после названия класса разрешается опускать,
если нет аргументов, которые требуется передать в конструктор класса.
Создание экземпляра класса
]]>
С PHP 8.0.0 поддерживается ключевое слово
new с произвольными выражениями.
Это разрешает создавать более сложные экземпляры, если
выражение создаёт строку (string).
Выражения берут в круглые скобки.
Пример новых объектов, которые создали через произвольные выражения
Пример показывает варианты допустимых произвольных выражений, которые представляют имя класса.
Пример вызова функции, конкатенации строк и константы ::class.
]]>
&example.outputs.8;
В контексте класса возможно создать новый объект
выражениями new self и new parent.
Переменная получит доступ к тому же экземпляру класса, что и объект,
который присвоили переменной.
Такое же поведение наблюдается при передаче экземпляра класса в функцию.
Копию объекта создают клонированием.
Присваивание объекта
var = 'У экземпляра класса, на который ссылается переменная $assigned, тоже будет это значение';
$instance = null; // Значения переменных $instance и $reference станут равны null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
]]>
&example.outputs;
string(152) "У экземпляра класса, на который ссылается переменная $assigned, тоже будет это значение"
}
]]>
Экземпляры объектов создают несколькими способами:
Новые объекты
]]>
&example.outputs;
К свойству или методу только что созданного объекта получится
обратиться одним выражением:
Доступ к свойствам и методам только что созданного объекта
format('Y'), PHP_EOL;
// Начиная с PHP 8.4.0 брать в скобки выражение new не обязательно
echo new DateTime()->format('Y'), PHP_EOL;
?>
]]>
&example.outputs.similar;
До PHP 7.1 язык не вычислял значения аргументов
в круглых скобках выражения, которым инстанциировали объект класса,
если в классе не было метода-конструктора.
Свойства и методы
Свойства и методы класса живут в отдельных «пространствах имён»,
поэтому свойства и методы допустимо называть одинаково.
У ссылок на свойства и методы одинаковая нотация, и получит
ли код доступ к свойству или вызовет метод — зависит только от контекста,
т. е. обращаются ли к переменной или вызывают функцию.
Сравнение доступа к свойству и вызова метода
bar, PHP_EOL, $obj->bar(), PHP_EOL;
?>
]]>
&example.outputs;
Из-за одинаковой нотации прямой вызов анонимной
функции, которую присвоили переменной, невозможен.
Вместо этого свойство вначале присваивают переменной, например.
Вызвать же анонимную функцию, которую сохранили в свойстве класса, напрямую получится,
если взять свойство в круглые скобки.
Вызов анонимной функции, которую содержит свойство
bar = function() {
return 42;
};
}
}
$obj = new Foo();
echo ($obj->bar)(), PHP_EOL;
?>
]]>
&example.outputs;
Ключевое слово extends
Класс умеет наследовать константы, методы и свойства другого класса через
ключевое слово extends в объявлении класса.
Невозможно наследовать больше одного класса, одному классу разрешено
наследовать только один базовый класс.
Константы, методы и свойства, которые унаследовал класс, разрешается переопределять
в дочернем классе путём повторного объявления с таким же именем, которое определили
в родительском классе.
Метод или константу нельзя переопределить, если в родительском классе метод
или константу определили окончательными — с ключевым словом
final.
Доступ к переопределённым методам или статическим свойствам родительского класса
получают, когда ссылаются на них через
parent::.
С PHP 8.1.0 разрешается объявлять константы окончательными.
Простое наследование классов
displayVar();
?>
]]>
&example.outputs;
Правила совместимости сигнатур
При переопределении метода сигнатура метода должна быть совместима
с родительским методом.
В противном случае PHP выдаст фатальную ошибку или, до PHP 8.0.0,
сгенерирует ошибку уровня E_WARNING.
Сигнатура совместима, если она соответствует правилам
вариантности,
делает обязательный параметр необязательным, добавляет только необязательные
новые параметры и не ограничивает, а только ослабляет видимость.
Эти правила называются принципом подстановки Барбары Лисков, или сокращённо LSP.
Правила совместимости не распространяются
на конструктор
и сигнатуру private-методов, и поэтому они не выдадут
фатальную ошибку, если сигнатура не соответствует.
Совместимость дочерних методов
foo();
$extended2 = new Extend2();
$extended2->foo(1);
?>
]]>
&example.outputs;
На следующих примерах видно, что дочерний метод, который
удаляет параметр или делает необязательный
параметр обязательным, несовместим с родительским методом.
Фатальная ошибка, когда дочерний метод удаляет параметр
]]>
&example.outputs.8.similar;
Фатальная ошибка, когда дочерний метод делает необязательный параметр обязательным
]]>
&example.outputs.8.similar;
Переименование параметра метода в дочернем классе не относится
к несовместимости сигнатуры. Однако это не рекомендуется, поскольку
приведёт к исключению Error во время выполнения,
если передавать
именованные аргументы.
Ошибка передачи именованных аргументов в параметры, которые переименовали
в дочернем классе
test(foo: "foo", bar: "bar"); // ОШИБКА!
?>
]]>
&example.outputs.similar;
Константа ::class
Ключевым словом class также разрешают имя класса.
Запись ClassName::class вернёт
абсолютное имя класса ClassName.
Это полезно при работе с классами, которые определили
в пространстве имён.
Разрешение имени класса
]]>
&example.outputs;
Разрешение имени класса через конструкцию ::class —
преобразование во время компиляции. Это означает, что в момент, когда
компилятор создаёт строку с именем класса, PHP ещё не выполнил
автозагрузку класса. Следствием этого становится то, что имена
классов разворачиваются, даже если класс не существует. При этом
ошибку PHP не выдаёт.
Разрешение имени несуществующего класса
]]>
&example.outputs;
Начиная с PHP 8.0.0 константа ::class научилась разрешать
имена объектов. Это разрешение константа совершает при выполнении кода, а компиляции.
Результат аналогичен вызову функции get_class на объекте.
Разрешение имени объекта
]]>
&example.outputs;
Null-безопасные методы и свойства
Оператор nullsafe появился в PHP 8.0.0 и разрешил безопасно
обращаться к свойствам и методам: ?->.
Null-безопасный оператор работает аналогично доступу к свойству или методу,
как описывали предыдущие параграфы,
за исключением возврата значения &null; вместо генерации исключения,
когда разыменовываемый объект равен &null;; PHP пропустит остаток цепочки обращений,
если разыменование в цепочке получит значение &null;.
Результат аналогичен предварительному оборачиванию каждого обращения
в функцию is_null, но более компактный.
Пример работы Nullsafe-оператора
getUser(5)?->name;
// эквивалентна следующему блоку кода:
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>
]]>
Оператором nullsafe лучше пользоваться, когда null рассматривается
как допустимое значение, которое, как ожидается, вернут свойство
или метод. Для указания на ошибку лучше выбрасывать исключение.