mirror of
https://github.com/php/doc-ru.git
synced 2026-03-24 07:42:22 +01:00
916 lines
29 KiB
XML
916 lines
29 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: fc068b4857342eb409efeafe6723058f39ab1045 Maintainer: sergey Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<sect1 xml:id="language.oop5.basic" xmlns="http://docbook.org/ns/docbook">
|
||
<title>Основы</title>
|
||
|
||
<sect2 xml:id="language.oop5.basic.class">
|
||
<title>class</title>
|
||
<para>
|
||
Каждое определение класса начинается с ключевого слова <literal>class</literal>, затем
|
||
идёт имя класса, а потом пара фигурных скобок, в которых определяют
|
||
свойства и методы класса.
|
||
</para>
|
||
<para>
|
||
Для класса разрешается выбирать произвольное название, при условии,
|
||
что это не <link linkend="reserved">зарезервированное слово</link> языка PHP.
|
||
Начиная с PHP 8.4.0 объявление названия класса, которое состоит из одного символа подчёркивания <literal>_</literal>,
|
||
устарело.
|
||
Допустимое название класса начинается с буквы или подчеркивания,
|
||
за которым идёт произвольное количество букв, цифр или символов подчеркивания.
|
||
В виде регулярного выражения правило именования классов выглядят так:
|
||
<code>^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$</code>.
|
||
</para>
|
||
<para>
|
||
Классы содержат <link linkend="language.oop5.constants">константы</link>,
|
||
<link linkend="language.oop5.properties">переменные</link>, которые в классах
|
||
называют свойствами, и функции, которые в классах называют методами.
|
||
</para>
|
||
<example>
|
||
<title>Простое определение класса</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class SimpleClass
|
||
{
|
||
// Объявление свойства
|
||
public $var = 'значение по умолчанию';
|
||
|
||
// Объявление метода
|
||
public function displayVar() {
|
||
echo $this->var;
|
||
}
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
<para>
|
||
Псевдопеременная <varname>$this</varname> доступна,
|
||
когда метод вызывается из контекста объекта.
|
||
Переменная <varname>$this</varname> — значение вызывающего объекта.
|
||
</para>
|
||
<warning>
|
||
<para>
|
||
Вызов нестатического метода статически выбрасывает исключение <classname>Error</classname>.
|
||
До PHP 8.0.0 это приводило к уведомлению об устаревании,
|
||
а переменная <varname>$this</varname> оставалась неопределённой.
|
||
</para>
|
||
<example xml:id="language.oop5.basic.class.this">
|
||
<title>Примеры псевдопеременной <varname>$this</varname></title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class A
|
||
{
|
||
function foo()
|
||
{
|
||
if (isset($this)) {
|
||
echo 'PHP определил переменную $this (';
|
||
echo get_class($this);
|
||
echo ")\n";
|
||
} else {
|
||
echo "PHP не определил переменную \$this.\n";
|
||
}
|
||
}
|
||
}
|
||
|
||
class B
|
||
{
|
||
function bar()
|
||
{
|
||
A::foo();
|
||
}
|
||
}
|
||
|
||
$a = new A();
|
||
$a->foo();
|
||
|
||
A::foo();
|
||
|
||
$b = new B();
|
||
$b->bar();
|
||
|
||
B::bar();
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.7;
|
||
<screen>
|
||
<![CDATA[
|
||
PHP определил переменную $this (A)
|
||
|
||
Deprecated: Non-static method A::foo() should not be called statically in %s on line 27
|
||
PHP не определил переменную $this.
|
||
|
||
Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
|
||
PHP не определил переменную $this.
|
||
|
||
Deprecated: Non-static method B::bar() should not be called statically in %s on line 32
|
||
|
||
Deprecated: Non-static method A::foo() should not be called statically in %s on line 20
|
||
PHP не определил переменную $this.
|
||
]]>
|
||
</screen>
|
||
&example.outputs.8;
|
||
<screen>
|
||
<![CDATA[
|
||
PHP определил переменную $this (A)
|
||
|
||
Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
|
||
Stack trace:
|
||
#0 {main}
|
||
thrown in %s on line 27
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</warning>
|
||
|
||
<sect3 xml:id="language.oop5.basic.class.readonly">
|
||
<title>Классы только для чтения</title>
|
||
<para>
|
||
Начиная с PHP 8.2.0 класс можно пометить
|
||
модификатором <modifier>readonly</modifier>.
|
||
Пометка класса как <modifier>readonly</modifier> добавит
|
||
<link linkend="language.oop5.properties.readonly-properties">модификатор <modifier>readonly</modifier></link>
|
||
к каждому объявленному свойству и не разрешит создавать
|
||
<link linkend="language.oop5.properties.dynamic-properties">динамические свойства</link>.
|
||
Поддержку динамических свойств невозможно добавить даже атрибутом
|
||
<classname>AllowDynamicProperties</classname>. Попытка это сделать вызовет ошибку компиляции.
|
||
</para>
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
#[\AllowDynamicProperties]
|
||
readonly class Foo {}
|
||
|
||
// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
|
||
<para>
|
||
В классах только для чтения нельзя объявлять нетипизированные и статические свойства,
|
||
поскольку такие свойства нельзя помечать модификатором <literal>readonly</literal>:
|
||
</para>
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
readonly class Foo
|
||
{
|
||
public $bar;
|
||
}
|
||
|
||
// Fatal error: Readonly property Foo::$bar must have type
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
readonly class Foo
|
||
{
|
||
public static int $bar;
|
||
}
|
||
|
||
// Fatal error: Readonly class Foo cannot declare static properties
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
<para>
|
||
Класс <modifier>readonly</modifier> получится
|
||
<link linkend="language.oop5.basic.extends">расширить</link>
|
||
тогда и только тогда, когда дочерний класс
|
||
тоже <modifier>readonly</modifier>-класс.
|
||
</para>
|
||
</sect3>
|
||
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.oop5.basic.new">
|
||
<title>Ключевое слово new</title>
|
||
<para>
|
||
Экземпляр класса создаётся директивой <literal>new</literal>.
|
||
Новый объект создаётся, если только
|
||
<link linkend="language.oop5.decon">конструктор</link> объекта
|
||
во время ошибки не выбрасывает <link linkend="language.exceptions">исключение</link>.
|
||
Класс рекомендуют определять перед тем, как создавать экземпляр класса;
|
||
иногда это обязательное требование.
|
||
</para>
|
||
<para>
|
||
PHP создаст новый экземпляр класса, если с ключевым словом
|
||
<literal>new</literal> указали переменную, которая содержит строку (<type>string</type>)
|
||
с названием класса.
|
||
Чтобы создать экземпляр класса, который определили в пространстве имён,
|
||
требуется указывать абсолютное имя класса.
|
||
</para>
|
||
|
||
<note>
|
||
<para>
|
||
Круглые скобки после названия класса разрешается опускать,
|
||
если нет аргументов, которые требуется передать в конструктор класса.
|
||
</para>
|
||
</note>
|
||
|
||
<example>
|
||
<title>Создание экземпляра класса</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class SimpleClass {}
|
||
|
||
$instance = new SimpleClass();
|
||
var_dump($instance);
|
||
|
||
// Или создаём экземпляр класса через переменную:
|
||
$className = 'SimpleClass';
|
||
$instance = new $className(); // Аналогично new SimpleClass()
|
||
var_dump($instance);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
<para>
|
||
С PHP 8.0.0 поддерживается ключевое слово
|
||
<literal>new</literal> с произвольными выражениями.
|
||
Это разрешает создавать более сложные экземпляры, если
|
||
выражение создаёт строку (<type>string</type>).
|
||
Выражения берут в круглые скобки.
|
||
</para>
|
||
<example>
|
||
<title>Пример новых объектов, которые создали через произвольные выражения</title>
|
||
<para>
|
||
Пример показывает варианты допустимых произвольных выражений, которые представляют имя класса.
|
||
Пример вызова функции, конкатенации строк и константы <constant>::class</constant>.
|
||
</para>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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));
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.8;
|
||
<screen>
|
||
<![CDATA[
|
||
object(ClassA)#1 (0) {
|
||
}
|
||
object(ClassB)#1 (0) {
|
||
}
|
||
object(ClassC)#1 (0) {
|
||
}
|
||
object(ClassD)#1 (0) {
|
||
}
|
||
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
В контексте класса возможно создать новый объект
|
||
выражениями <literal>new self</literal> и <literal>new parent</literal>.
|
||
</para>
|
||
<para>
|
||
Переменная получит доступ к тому же экземпляру класса, что и объект,
|
||
который присвоили переменной.
|
||
Такое же поведение наблюдается при передаче экземпляра класса в функцию.
|
||
Копию объекта создают <link linkend="language.oop5.cloning">клонированием</link>.
|
||
</para>
|
||
<example>
|
||
<title>Присваивание объекта</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class SimpleClass
|
||
{
|
||
public string $var;
|
||
}
|
||
|
||
$instance = new SimpleClass();
|
||
|
||
$assigned = $instance;
|
||
$reference =& $instance;
|
||
|
||
$instance->var = 'У экземпляра класса, на который ссылается переменная $assigned, тоже будет это значение';
|
||
|
||
$instance = null; // Значения переменных $instance и $reference станут равны null
|
||
|
||
var_dump($instance);
|
||
var_dump($reference);
|
||
var_dump($assigned);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
NULL
|
||
NULL
|
||
object(SimpleClass)#1 (1) {
|
||
["var"]=>
|
||
string(152) "У экземпляра класса, на который ссылается переменная $assigned, тоже будет это значение"
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
Экземпляры объектов создают несколькими способами:
|
||
</para>
|
||
<example>
|
||
<title>Новые объекты</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Test
|
||
{
|
||
public static 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);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
bool(true)
|
||
bool(true)
|
||
bool(true)
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
К свойству или методу только что созданного объекта получится
|
||
обратиться одним выражением:
|
||
</para>
|
||
<example>
|
||
<title>Доступ к свойствам и методам только что созданного объекта</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
echo (new DateTime())->format('Y'), PHP_EOL;
|
||
|
||
// Начиная с PHP 8.4.0 брать в скобки выражение new не обязательно
|
||
echo new DateTime()->format('Y'), PHP_EOL;
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
2025
|
||
2025
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
|
||
<note>
|
||
<simpara>
|
||
До PHP 7.1 язык не вычислял значения аргументов
|
||
в круглых скобках выражения, которым инстанциировали объект класса,
|
||
если в классе не было метода-конструктора.
|
||
</simpara>
|
||
</note>
|
||
</sect2>
|
||
<sect2 xml:id="language.oop5.basic.properties-methods">
|
||
<title>Свойства и методы</title>
|
||
<para>
|
||
Свойства и методы класса живут в отдельных «пространствах имён»,
|
||
поэтому свойства и методы допустимо называть одинаково.
|
||
У ссылок на свойства и методы одинаковая нотация, и получит
|
||
ли код доступ к свойству или вызовет метод — зависит только от контекста,
|
||
т. е. обращаются ли к переменной или вызывают функцию.
|
||
</para>
|
||
<example>
|
||
<title>Сравнение доступа к свойству и вызова метода</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
public $bar = 'свойство';
|
||
|
||
public function bar()
|
||
{
|
||
return 'метод';
|
||
}
|
||
}
|
||
|
||
$obj = new Foo();
|
||
echo $obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
свойство
|
||
метод
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<para>
|
||
Из-за одинаковой нотации прямой вызов <link linkend="functions.anonymous">анонимной
|
||
функции</link>, которую присвоили переменной, невозможен.
|
||
Вместо этого свойство вначале присваивают переменной, например.
|
||
Вызвать же анонимную функцию, которую сохранили в свойстве класса, напрямую получится,
|
||
если взять свойство в круглые скобки.
|
||
</para>
|
||
<example>
|
||
<title>Вызов анонимной функции, которую содержит свойство</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
public $bar;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->bar = function() {
|
||
return 42;
|
||
};
|
||
}
|
||
}
|
||
|
||
$obj = new Foo();
|
||
|
||
echo ($obj->bar)(), PHP_EOL;
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
42
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</sect2>
|
||
<sect2 xml:id="language.oop5.basic.extends">
|
||
<!-- TODO Example about class constant redefinition -->
|
||
<!-- TODO Split into it's own page? -->
|
||
<title>Ключевое слово extends</title>
|
||
<para>
|
||
Класс умеет наследовать константы, методы и свойства другого класса через
|
||
ключевое слово <literal>extends</literal> в объявлении класса.
|
||
Невозможно наследовать больше одного класса, одному классу разрешено
|
||
наследовать только один базовый класс.
|
||
</para>
|
||
<para>
|
||
Константы, методы и свойства, которые унаследовал класс, разрешается переопределять
|
||
в дочернем классе путём повторного объявления с таким же именем, которое определили
|
||
в родительском классе.
|
||
Метод или константу нельзя переопределить, если в родительском классе метод
|
||
или константу определили окончательными — с ключевым словом
|
||
<link linkend="language.oop5.final">final</link>.
|
||
Доступ к переопределённым методам или статическим свойствам родительского класса
|
||
получают, когда ссылаются на них через
|
||
<link linkend="language.oop5.paamayim-nekudotayim">parent::</link>.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
С PHP 8.1.0 разрешается объявлять константы окончательными.
|
||
</simpara>
|
||
</note>
|
||
<example>
|
||
<title>Простое наследование классов</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class SimpleClass
|
||
{
|
||
function displayVar()
|
||
{
|
||
echo "Родительский класс\n";
|
||
}
|
||
}
|
||
|
||
class ExtendClass extends SimpleClass
|
||
{
|
||
// Переопределение родительского метода
|
||
function displayVar()
|
||
{
|
||
echo "Дочерний класс\n";
|
||
parent::displayVar();
|
||
}
|
||
}
|
||
|
||
$extended = new ExtendClass();
|
||
$extended->displayVar();
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Дочерний класс
|
||
Родительский класс
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
|
||
<sect3 xml:id="language.oop.lsp">
|
||
<title>Правила совместимости сигнатур</title>
|
||
<para>
|
||
При переопределении метода сигнатура метода должна быть совместима
|
||
с родительским методом.
|
||
В противном случае PHP выдаст фатальную ошибку или, до PHP 8.0.0,
|
||
сгенерирует ошибку уровня <constant>E_WARNING</constant>.
|
||
Сигнатура совместима, если она соответствует правилам
|
||
<link linkend="language.oop5.variance">вариантности</link>,
|
||
делает обязательный параметр необязательным, добавляет только необязательные
|
||
новые параметры и не ограничивает, а только ослабляет видимость.
|
||
Эти правила называются принципом подстановки Барбары Лисков, или сокращённо LSP.
|
||
Правила совместимости не распространяются
|
||
<link linkend="language.oop5.decon.constructor">на конструктор</link>
|
||
и сигнатуру <literal>private</literal>-методов, и поэтому они не выдадут
|
||
фатальную ошибку, если сигнатура не соответствует.
|
||
</para>
|
||
<example>
|
||
<title>Совместимость дочерних методов</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Base
|
||
{
|
||
public function foo(int $a)
|
||
{
|
||
echo "Допустимо\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);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Допустимо
|
||
Допустимо
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
|
||
<para>
|
||
На следующих примерах видно, что дочерний метод, который
|
||
удаляет параметр или делает необязательный
|
||
параметр обязательным, несовместим с родительским методом.
|
||
</para>
|
||
<example>
|
||
<title>Фатальная ошибка, когда дочерний метод удаляет параметр</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Base
|
||
{
|
||
public function foo(int $a = 5)
|
||
{
|
||
echo "Допустимо\n";
|
||
}
|
||
}
|
||
|
||
class Extend extends Base
|
||
{
|
||
function foo()
|
||
{
|
||
parent::foo(1);
|
||
}
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.8.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
<example>
|
||
<title>
|
||
Фатальная ошибка, когда дочерний метод делает необязательный параметр обязательным
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Base
|
||
{
|
||
public function foo(int $a = 5)
|
||
{
|
||
echo "Допустимо\n";
|
||
}
|
||
}
|
||
|
||
class Extend extends Base
|
||
{
|
||
function foo(int $a)
|
||
{
|
||
parent::foo($a);
|
||
}
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.8.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
|
||
<warning>
|
||
<para>
|
||
Переименование параметра метода в дочернем классе не относится
|
||
к несовместимости сигнатуры. Однако это не рекомендуется, поскольку
|
||
приведёт к исключению <classname>Error</classname> во время выполнения,
|
||
если передавать
|
||
<link linkend="functions.named-arguments">именованные аргументы</link>.
|
||
</para>
|
||
<example>
|
||
<title>
|
||
Ошибка передачи именованных аргументов в параметры, которые переименовали
|
||
в дочернем классе
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class A
|
||
{
|
||
public function test($foo, $bar) {}
|
||
}
|
||
|
||
class B extends A
|
||
{
|
||
public function test($a, $b) {}
|
||
}
|
||
|
||
$obj = new B();
|
||
|
||
// Передача параметров согласно контракту метода A::test()
|
||
$obj->test(foo: "foo", bar: "bar"); // ОШИБКА!
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.similar;
|
||
<screen>
|
||
<![CDATA[
|
||
Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
|
||
Stack trace:
|
||
#0 {main}
|
||
thrown in /in/XaaeN on line 14
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</warning>
|
||
</sect3>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.oop5.basic.class.class">
|
||
<title>Константа ::class</title>
|
||
|
||
<para>
|
||
Ключевым словом <literal>class</literal> также разрешают имя класса.
|
||
Запись <literal>ClassName::class</literal> вернёт
|
||
абсолютное имя класса <literal>ClassName</literal>.
|
||
Это полезно при работе с классами, которые определили
|
||
<link linkend="language.namespaces">в пространстве имён</link>.
|
||
</para>
|
||
<para>
|
||
<example xml:id="language.oop5.basic.class.class.name">
|
||
<title>Разрешение имени класса</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
namespace NS {
|
||
class ClassName {}
|
||
|
||
echo ClassName::class;
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
NS\ClassName
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<note>
|
||
<para>
|
||
Разрешение имени класса через конструкцию <literal>::class</literal> —
|
||
преобразование во время компиляции. Это означает, что в момент, когда
|
||
компилятор создаёт строку с именем класса, PHP ещё не выполнил
|
||
автозагрузку класса. Следствием этого становится то, что имена
|
||
классов разворачиваются, даже если класс не существует. При этом
|
||
ошибку PHP не выдаёт.
|
||
</para>
|
||
<example xml:id="language.oop5.basic.class.class.fail">
|
||
<title>Разрешение имени несуществующего класса</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
print Does\Not\Exist::class;
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Does\Not\Exist
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</note>
|
||
<para>
|
||
Начиная с PHP 8.0.0 константа <literal>::class</literal> научилась разрешать
|
||
имена объектов. Это разрешение константа совершает при выполнении кода, а компиляции.
|
||
Результат аналогичен вызову функции <function>get_class</function> на объекте.
|
||
</para>
|
||
<example xml:id="language.oop5.basic.class.class.object">
|
||
<title>Разрешение имени объекта</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
namespace NS {
|
||
class ClassName {}
|
||
|
||
$c = new ClassName();
|
||
print $c::class;
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
NS\ClassName
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</sect2>
|
||
<sect2 xml:id="language.oop5.basic.nullsafe">
|
||
<title>Null-безопасные методы и свойства</title>
|
||
<para>
|
||
Оператор nullsafe появился в PHP 8.0.0 и разрешил безопасно
|
||
обращаться к свойствам и методам: <literal>?-></literal>.
|
||
Null-безопасный оператор работает аналогично доступу к свойству или методу,
|
||
как описывали предыдущие параграфы,
|
||
за исключением возврата значения &null; вместо генерации исключения,
|
||
когда разыменовываемый объект равен &null;; PHP пропустит остаток цепочки обращений,
|
||
если разыменование в цепочке получит значение &null;.
|
||
</para>
|
||
<para>
|
||
Результат аналогичен предварительному оборачиванию каждого обращения
|
||
в функцию <function>is_null</function>, но более компактный.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Пример работы Nullsafe-оператора</title>
|
||
<programlisting role="php" annotations="non-interactive">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Начиная с PHP 8.0.0 эта строка:
|
||
$result = $repository?->getUser(5)?->name;
|
||
|
||
// эквивалентна следующему блоку кода:
|
||
if (is_null($repository)) {
|
||
$result = null;
|
||
} else {
|
||
$user = $repository->getUser(5);
|
||
|
||
if (is_null($user)) {
|
||
$result = null;
|
||
} else {
|
||
$result = $user->name;
|
||
}
|
||
}
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<note>
|
||
<para>
|
||
Оператором nullsafe лучше пользоваться, когда null рассматривается
|
||
как допустимое значение, которое, как ожидается, вернут свойство
|
||
или метод. Для указания на ошибку лучше выбрасывать исключение.
|
||
</para>
|
||
</note>
|
||
</sect2>
|
||
</sect1>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|