PHP включает полную объектную модель. Некоторые из его особенностей: видимость , абстрактные и окончательные классы и методы, дополнительные магические методы , интерфейсы и клонирование .
PHP обрабатывает объекты так же, как ссылки или дескрипторы, что означает, что каждая переменная содержит ссылку на объект, а не копию всего объекта.
Основные определения классов начинаются с ключевого слова class
, за которым следует имя класса, за которым следует пара фигурных скобок, заключающих в себе определения свойств и методов, принадлежащих классу.
Имя класса может быть любой допустимой меткой, при условии, что это не зарезервированное слово PHP . Допустимое имя класса начинается с буквы или знака подчеркивания, за которым следует любое количество букв, цифр или знаков подчеркивания. В качестве регулярного выражения это будет выглядеть так: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$
.
Класс может содержать свои собственные константы , переменные (называемые «свойствами») и функции (называемые «методами»).
Пример #1 Простое определение класса
<?php
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
Псевдопеременная $this доступна, когда метод вызывается из контекста объекта. $это значение вызывающего объекта.
Предупреждение
Вызов нестатического метода статически вызывает ошибку . До PHP 8.0.0 это генерировало уведомление об устаревании, а $this было неопределенным.
Пример #2 Некоторые примеры использования псевдопеременной $this
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
New
Чтобы создать экземпляр класса, new
необходимо использовать ключевое слово. Объект всегда будет создаваться, если для объекта не определен конструктор , который выдает исключение при ошибке. Классы должны быть определены до создания экземпляра (и в некоторых случаях это требование).
Если строка , содержащая имя класса, используется с new
, будет создан новый экземпляр этого класса. Если класс находится в пространстве имен, при этом должно использоваться его полное имя.
Примечание :
Если нет аргументов для передачи конструктору класса, круглые скобки после имени класса могут быть опущены.
Пример #3 Создание экземпляра
<?php
$instance = new SimpleClass();
// This can also be done with a variable:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>
Начиная с PHP 8.0.0 поддерживается использование new
с произвольными выражениями. Это позволяет создавать более сложные экземпляры, если выражение создает строку . Выражения должны быть заключены в круглые скобки.
Пример #4 Создание экземпляра с помощью произвольного выражения
В данном примере мы показываем несколько примеров допустимых произвольных выражений, которые создают имя класса. Это показывает вызов функции, конкатенацию строк и ::class
константу.
<?php
class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}
function getSomeClass(): string
{
return 'ClassA';
}
var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>
Вывод приведенного выше примера в PHP 8:
объект (класс A) № 1 (0 ) { } объект (класс B) № 1 (0) { } объект (класс C) № 1 (0) { } объект (класс D) № 1 (0) { }
В контексте класса можно создать новый объект с помощью new self
и new parent
.
При назначении уже созданного экземпляра класса новой переменной новая переменная будет обращаться к тому же экземпляру, что и назначенный объект. Такое же поведение происходит при передаче экземпляров в функцию. Копию уже созданного объекта можно сделать, клонировав его.
Пример #5 Назначение объекта
<?php
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
Приведенный выше пример выведет:
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned будет иметь это значение"
}
Экземпляры объекта можно создать несколькими способами:
Пример #6 Создание новых объектов
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
Приведенный выше пример выведет:
логическое (истинное)
логическое (истинное)
логическое (истинное)
Можно получить доступ к члену вновь созданного объекта в одном выражении:
Пример #7 Доступ к члену только что созданного объекта
<?php
echo (new DateTime())->format('Y');
?>
Приведенный выше пример выведет что-то похожее на: 2016
Примечание . До версии PHP 7.1 аргументы не оценивались, если функция-конструктор не определена.
Свойства и методы
Свойства и методы класса находятся в отдельных «пространствах имен», поэтому свойство и метод могут иметь одно и то же имя. Ссылка как на свойство, так и на метод имеет одинаковую нотацию, и будет ли осуществляться доступ к свойству или будет вызываться метод, зависит исключительно от контекста, т. е. от того, является ли использование доступом к переменной или вызовом функции.
Пример #8 Доступ к свойству и вызов метода
<?php
class Foo
{
public $bar = 'property';
public function bar() {
return 'method';
}
}
$obj = new Foo();
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;
Приведенный выше пример выведет: method property
Это означает, что вызов анонимной функции , назначенной свойству, напрямую невозможен. Вместо этого свойство должно быть сначала присвоено, например, переменной. Такое свойство можно вызвать напрямую, заключив его в круглые скобки.
Пример #9 Вызов анонимной функции, хранящейся в свойстве
<?php
class Foo
{
public $bar;
public function __construct() {
$this->bar = function() {
return 42;
};
}
}
$obj = new Foo();
echo ($obj->bar)(), PHP_EOL;
Приведенный выше пример выведет: 42
Extend
Класс может наследовать константы, методы и свойства другого класса, используя ключевое слово extends
в объявлении класса. Невозможно расширить несколько классов; класс может наследовать только от одного базового класса.
Унаследованные константы, методы и свойства можно переопределить, повторно объявив их с тем же именем, которое определено в родительском классе. Однако, если родительский класс определил метод или константу как final , они не могут быть переопределены. Доступ к переопределенным методам или статическим свойствам можно получить, сославшись на них с помощью parent:: .
Примечание . Начиная с PHP 8.1.0, константы могут быть объявлены как final.
Пример #10 Простое наследование классов
<?php
class ExtendClass extends SimpleClass
{
// Redefine the parent method
function displayVar()
{
echo "Extending class\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
Приведенный выше пример выведет:
Расширение класса
значением по умолчанию
Правила совместимости подписи
При переопределении метода его подпись должна быть совместима с родительским методом. В противном случае выдается фатальная ошибка или, до версии PHP 8.0.0, генерируется E_WARNING
ошибка уровня. Подпись совместима, если она соблюдает правила отклонения , делает обязательный параметр необязательным и если любые новые параметры являются необязательными. Это известно как принцип замещения Лискова, или сокращенно LSP. Конструктор и методы освобождены от этих правил совместимости сигнатур и, таким образом, не будут выдавать фатальную ошибку в случае несоответствия сигнатуры private
Пример #11 Совместимые дочерние методы
<?php
class Base
{
public function foo(int $a) {
echo "Valid\n";
}
}
class Extend1 extends Base
{
function foo(int $a = 5)
{
parent::foo($a);
}
}
class Extend2 extends Base
{
function foo(int $a, $b = 5)
{
parent::foo($a);
}
}
$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);
Приведенный выше пример выведет:
Valid Valid
В следующих примерах показано, что дочерний метод, который удаляет параметр или делает необязательный параметр обязательным, несовместим с родительским методом.
Пример #12 Фатальная ошибка, когда дочерний метод удаляет параметр
<?php
class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}
class Extend extends Base
{
function foo()
{
parent::foo(1);
}
}
Вывод приведенного выше примера в PHP 8 аналогичен:
Неустранимая ошибка: объявление Extend::foo() должно быть совместимо с Base::foo(int $a = 5) в /in/evtlq в строке 13.
Пример #13 Фатальная ошибка, когда дочерний метод делает необязательный параметр обязательным
<?php
class Base
{
public function foo(int $a = 5) {
echo "Valid\n";
}
}
class Extend extends Base
{
function foo(int $a)
{
parent::foo($a);
}
}
Вывод приведенного выше примера в PHP 8 аналогичен:
Неустранимая ошибка: объявление Extend::foo(int $a) должно быть совместимо с Base::foo(int $a = 5) в /in/qJXVC в строке 13.
Предупреждение
Переименование параметра метода в дочернем классе не является несовместимостью сигнатур. Однако это не рекомендуется, так как это приведет к ошибке времени выполнения , если используются именованные аргументы .
Пример #14 Ошибка при использовании именованных аргументов и переименовании параметров в дочернем классе
<?php
class A {
public function test($foo, $bar) {}
}
class B extends A {
public function test($a, $b) {}
}
$obj = new B;
// Pass parameters according to A::test() contract
$obj->test(foo: "foo", bar: "bar"); // ERROR!
Приведенный выше пример выведет что-то похожее на:
Неустранимая ошибка: Uncaught Error: Неизвестный именованный параметр $foo в /in/XaaeN:14
Трассировка стека:
#0 {main}
добавлено в /in/XaaeN в строке 14
::class
Ключевое class
слово также используется для разрешения имени класса. Чтобы получить полное имя класса, ClassName
используйте ClassName::class
. Это особенно полезно для классов с пространством имен .
Пример #15 Разрешение имени класса
<?php
namespace NS {
class ClassName {
}
echo ClassName::class;
}
?>
Приведенный выше пример выведет:
NS\ClassName
Примечание :
Использование разрешения имени класса
::class
— это преобразование времени компиляции. Это означает, что на момент создания строки имени класса автозагрузка еще не произошла. Как следствие, имена классов расширяются, даже если класс не существует. В этом случае ошибка не выдается.Пример #16 Отсутствует разрешение имени класса
<?php print Does\Not\Exist::class; ?>
Приведенный выше пример выведет:
Не существует
Начиная с PHP 8.0.0, эту ::class
константу также можно использовать для объектов. Это разрешение происходит во время выполнения, а не во время компиляции. Его действие такое же, как при вызове get_class() для объекта.
Пример #17 Разрешение имени объекта
<?php
namespace NS {
class ClassName {
}
}
$c = new ClassName();
print $c::class;
?>
Приведенный выше пример выведет:
NS\ClassName
Nullsafe методы и свойства
Начиная с PHP 8.0.0, свойства и методы также могут быть доступны с помощью оператора «nullsafe»: ?->
. Оператор nullsafe работает так же, как доступ к свойству или методу, как описано выше, за исключением того, что если разыменованный объект null
будет null
возвращен, а не будет выдано исключение. Если разыменование является частью цепочки, остальная часть цепочки пропускается.
Эффект похож на то, как если бы сначала каждый доступ был заключен в проверку is_null() , но более компактный.
Пример #18 Оператор Nullsafe
<?php
// As of PHP 8.0.0, this line:
$result = $repository?->getUser(5)?->name;
// Is equivalent to the following code block:
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>
0 комментариев