Конструктор
__construct(
mixed ...$values
= ""):
void
PHP позволяет объявлять методы-конструкторы. Классы, в которых
объявлен метод-конструктор, будут вызывать этот метод при каждом
создании нового объекта, так что это может оказаться полезным,
например, для инициализации какого-либо состояния объекта
перед его использованием.
Замечание:
Конструкторы, определённые в классах-родителях, не вызываются автоматически,
если дочерний класс определяет собственный конструктор.
Чтобы вызвать конструктор, объявленный в родительском классе,
требуется вызвать parent::__construct()
внутри конструктора дочернего класса. Если в дочернем классе
не определён конструктор, то он может быть унаследован от
родительского класса как обычный метод (если он не был
определён как приватный).
Пример #1 Конструкторы при наследовании
<?php
class BaseClass {
function __construct() {
print "Конструктор класса BaseClass\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "Конструктор класса SubClass\n";
}
}
class OtherSubClass extends BaseClass {
// наследует конструктор BaseClass
}
// Конструктор класса BaseClass
$obj = new BaseClass();
// Конструктор класса BaseClass
// Конструктор класса SubClass
$obj = new SubClass();
// Конструктор класса BaseClass
$obj = new OtherSubClass();
?>
В отличие от других методов, __construct()
освобождается от обычных правил совместимости сигнатуры при наследовании.
Конструкторы - это обычные методы, которые вызываются при
инстанциировании соответствующих объектов. Следовательно, они могут иметь
произвольное количество аргументов, которые могут быть обязательными, могут
быть типизированными и могут иметь значения по умолчанию. Аргументы конструктора
указываются в круглых скобках после имени класса.
Пример #2 Использование аргументов в конструкторах
<?php
class Point {
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0) {
$this->x = $x;
$this->y = $y;
}
}
// Передаём оба параметра.
$p1 = new Point(4, 5);
// Передаём только обязательные параметры. Для $y используется значение по умолчанию 0.
$p2 = new Point(4);
// Вызываем с именованными параметрами (начиная с PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>
Если у класса нет конструктора, или его конструктор не имеет обязательных параметров, скобки
после имени класса можно не писать.
Конструкторы в старом стиле
До PHP 8.0.0, классы в глобальном пространстве имён будут интерпретировать метод,
названный так же, как класс, как конструктор старого стиля. Этот синтаксис считается
устаревшим и будет вызывать ошибку уровня E_DEPRECATED
, но
всё равно эти методы будут вызываться в качестве конструктора.
Если в классе присутствуют и __construct(),
и метод с именем класса, то в качестве конструктора будет вызван
__construct().
Для классов, находящихся в собственном пространстве имён и для всех классов, начиная с
PHP 8.0.0, метод, названный по имени класса, будет игнорироваться.
В новом коде всегда используйте __construct().
New в инициализации класса
Начиная с PHP 8.1.0, объекты можно использовать в качестве значений параметров по умолчанию,
статических переменных и глобальных констант, а также в аргументах атрибутов.
Объекты также теперь можно передавать в define().
Замечание:
Использование динамического или не строкового имени класса или анонимного класса не допускается.
Использование распаковки аргументов не допускается.
Использование неподдерживаемых выражений в качестве аргументов не допускается.
Пример #4 Пример использования new в инициализации класса
<?php
// Всё допустимо:
static $x = new Foo;
const C = new Foo;
function test($param = new Foo) {}
#[AnAttribute(new Foo)]
class Test {
public function __construct(
public $prop = new Foo,
) {}
}
// Всё не допустимо (ошибка во времени компиляции):
function test(
$a = new (CLASS_NAME_CONSTANT)(), // динамическое имя класса
$b = new class {}, // анонимный класс
$c = new A(...[]), // распаковка аргументов
$d = new B($abc), // неподдерживаемое постоянное выражение
) {}
?>
Статические методы создания объекта
PHP поддерживает только один конструктор для класса. Однако в некоторых случаях есть
необходимость создавать объект разными путями в зависимости от разных входных данных.
Рекомендуемый способ - использовать статические методы как обёртки над конструктором.
Пример #5 Использование статических методов для создания объектов
<?php
class Product {
private ?int $id;
private ?string $name;
private function __construct(?int $id = null, ?string $name = null) {
$this->id = $id;
$this->name = $name;
}
public static function fromBasicData(int $id, string $name): static {
$new = new static($id, $name);
return $new;
}
public static function fromJson(string $json): static {
$data = json_decode($json);
return new static($data['id'], $data['name']);
}
public static function fromXml(string $xml): static {
// Пользовательская логика.
$data = convert_xml_to_array($xml);
$new = new static();
$new->id = $data['id'];
$new->name = $data['name'];
return $new;
}
}
$p1 = Product::fromBasicData(5, 'Widget');
$p2 = Product::fromJson($some_json_string);
$p3 = Product::fromXml($some_xml_string);
Конструктор можно сделать скрытым или защищённым для предотвращения его прямого вызова.
В таком случае объект класса можно будет создать только с помощью статических
методов. Так как это методы того же класса, они имеют доступ ко всем его скрытым
методам, даже если они относятся к разным экземплярам класса. Скрытый конструктор
опционален и может присутствовать или отсутствовать по необходимости.
В примере выше три публичных статических метода демонстрируют различные способы
создания экземпляра объекта.
fromBasicData()
принимает явные параметры, создаёт экземпляр
класса через конструктор и возвращает объект.
fromJson()
принимает JSON строку, производит над ней некоторые
преобразования, извлекает данные необходимые для создания объекта и, так же как и
предыдущий метод, вызывает конструктор и возвращает созданный объект.
fromXml()
принимает XML строку, извлекает нужные данные и, так
как в конструкторе нет обязательных параметров, вызывает его без них. После этого, так
как ему доступны скрытые свойства, он присваивает им значения напрямую. После чего
возвращает готовый объект.
Во всех трёх случаях, ключевое слово static
транслируется в имя класса,
в котором этот код вызывается. В нашем случае Product
.
Деструкторы
__destruct(): void
PHP предоставляет концепцию деструктора, аналогичную с той, которая
применяется в других ОО-языках, таких как C++.
Деструктор будет вызван при освобождении всех ссылок
на определённый объект или при завершении
скрипта (порядок выполнения деструкторов не гарантируется).
Пример #6 Пример использования деструктора
<?php
class MyDestructableClass
{
function __construct() {
print "Конструктор\n";
}
function __destruct() {
print "Уничтожается " . __CLASS__ . "\n";
}
}
$obj = new MyDestructableClass();
Как и в случае с конструкторами, деструкторы, объявленные
в родительском классе, не будут вызываться автоматически.
Для вызова деструктора родительского класса,
требуется вызвать parent::__destruct() в
теле деструктора дочернего класса. Подобно конструкторам, дочерний класс может унаследовать
деструктор из родительского класса, если он не определён в нем.
Деструктор будет вызываться даже в том случае, если скрипт был остановлен с
помощью функции exit(). Вызов exit()
в деструкторе предотвратит запуск всех последующих функций завершения.
Замечание:
Деструкторы, вызываемые при завершении скрипта, вызываются после отправки
HTTP-заголовков. Рабочая директория во время фазы завершения скрипта
может отличаться в некоторых SAPI (например, в Apache).
Замечание:
Попытка выбросить исключение из деструктора (вызываемого во время
завершения скрипта) вызывает фатальную ошибку.