Основыclass
Каждое определение класса начинается с ключевого слова class, затем
идёт имя класса, а потом пара фигурных скобок, в которых определяют
свойства и методы класса.
Для имени класса разрешается выбирать любое слово, при условии, что слово не входит в список
зарезервированных слов PHP, начинается с буквы или
символа подчёркивания и за которым следует любое количество букв, цифр или символов
подчёркивания. Если задать эти правила в виде регулярного выражения, то получится
следующее выражение: ^[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(30) "$assigned будет иметь это значение"
}
]]>
Экземпляры объектов создают несколькими способами:
Новые объекты
]]>
&example.outputs;
К свойству или методу только что созданного объекта получится
обратиться одним выражением:
Доступ к свойствам и методам только что созданного объекта
format('Y');
?>
]]>
&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;
Методы и свойства Nullsafe
Начиная с PHP 8.0.0 к свойствам и методам можно также
обращаться через оператор nullsafe: ?->.
Оператор nullsafe работает так же, как доступ к свойству или методу,
как описание рассказывало выше,
за исключением того, что если значение разыменовываемого объекта равно &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 рассматривается
как допустимое значение, которое, как ожидается, вернут свойство
или метод. Для указания на ошибку лучше выбрасывать исключение.