PHP позволяет разработчикам объявлять методы конструктора для классов. Классы, у которых есть метод конструктора, вызывают этот метод для каждого вновь созданного объекта, поэтому он подходит для любой инициализации, которая может потребоваться объекту перед его использованием.

Примечание . Родительские конструкторы не вызываются неявно, если дочерний класс определяет конструктор. Чтобы запустить родительский конструктор, требуется вызов parent::__construct() внутри дочернего конструктора. Если дочерний элемент не определяет конструктор, он может быть унаследован от родительского класса точно так же, как обычный метод класса (если он не был объявлен как закрытый).

Пример #1 Конструкторы в наследовании

<?php
class BaseClass {
    function __construct() {
        print "In BaseClass constructor\n";
    }
}

class SubClass extends BaseClass {
    function __construct() {
        parent::__construct();
        print "In SubClass constructor\n";
    }
}

class OtherSubClass extends BaseClass {
    // inherits BaseClass's constructor
}

// In BaseClass constructor
$obj = new BaseClass();

// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();

// In BaseClass constructor
$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;
    }
}

// Pass both parameters.
$p1 = new Point(4, 5);
// Pass only the required parameter. $y will take its default value of 0.
$p2 = new Point(4);
// With named parameters (as of PHP 8.0):
$p3 = new Point(y: 5, x: 4);
?>

Если у класса нет конструктора или у конструктора нет обязательных аргументов, круглые скобки можно опустить.

Конструкторы старого образца

До версии PHP 8.0.0 классы в глобальном пространстве имен интерпретировали метод с тем же именем, что и класс, как конструктор старого стиля. Этот синтаксис устарел и приведет к E_DEPRECATEDошибке, но по-прежнему будет вызывать эту функцию как конструктор. Если определены и __construct() , и одноименный метод, будет вызван __construct() .

В классах с пространством имен или любом другом классе, начиная с PHP 8.0.0, метод с тем же именем, что и у класса, никогда не имеет особого значения.

Всегда используйте __construct() в новом коде.

Продвижение конструктора

Начиная с PHP 8.0.0, параметры конструктора также могут повышаться, чтобы соответствовать свойству объекта. Очень часто параметры конструктора назначаются свойству в конструкторе, но в противном случае не используются. Продвижение конструктора обеспечивает сокращение для этого варианта использования. Приведенный выше пример можно переписать следующим образом.

Пример #3 Использование продвижения свойства конструктора

<?php
class Point {
    public function __construct(protected int $x, protected int $y = 0) {
    }
}

Когда аргумент конструктора включает модификатор видимости, PHP интерпретирует его и как свойство объекта, и как аргумент конструктора, и присваивает значение аргумента свойству. В этом случае тело конструктора может быть пустым или содержать другие операторы. Любые дополнительные операторы будут выполняться после того, как значения аргументов будут присвоены соответствующим свойствам.

Не все аргументы нужно продвигать. Можно смешивать и сопоставлять продвигаемые и не продвигаемые аргументы в любом порядке. Продвинутые аргументы не влияют на код, вызывающий конструктор.

Примечание :

Свойства объекта не могут быть типизированы вызываемыми из-за двусмысленности движка, которая может ввести. Таким образом, продвинутые аргументы также не могут быть типизированы вызываемыми . Однако допускается любое другое объявление типа .

Примечание :

Атрибуты , помещенные в продвинутый аргумент конструктора, будут реплицированы как в свойство, так и в аргумент.

Новое в инициализаторах

Начиная с PHP 8.1.0, объекты можно использовать в качестве значений параметров по умолчанию, статических переменных и глобальных констант, а также в качестве аргументов атрибутов. Теперь объекты также можно передавать в функцию define() .

Примечание :

Использование динамического или нестрокового имени класса или анонимного класса не допускается. Использование распаковки аргумента не допускается. Использование неподдерживаемых выражений в качестве аргументов не допускается.

Пример #4 Использование new в инициализаторах

<?php

// All allowed:
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,
    ) {}
}

// All not allowed (compile-time error):
function test(
    $a = new (CLASS_NAME_CONSTANT)(), // dynamic class name
    $b = new class {}, // anonymous class
    $c = new A(...[]), // argument unpacking
    $d = new B($abc), // unsupported constant expression
) {}
?>

Статические методы создания

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 {
        // Custom logic here.
        $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

__destruct (): недействительным

PHP имеет концепцию деструктора, аналогичную концепции других объектно-ориентированных языков, таких как C++. Метод деструктора будет вызван, как только не будет других ссылок на конкретный объект или в любом порядке во время последовательности завершения работы.

Пример #6 Пример деструктора

<?php

class MyDestructableClass 
{
    function __construct() {
        print "In constructor\n";
    }

    function __destruct() {
        print "Destroying " . __CLASS__ . "\n";
    }
}

$obj = new MyDestructableClass();

Как и конструкторы, родительские деструкторы не будут вызываться движком неявно. Чтобы запустить родительский деструктор, нужно было бы явно вызвать parent::__destruct() в теле деструктора. Также, как и конструкторы, дочерний класс может наследовать деструктор родителя, если он сам не реализует его.

Деструктор будет вызван, даже если выполнение скрипта будет остановлено с помощью exit() . Вызов exit() в деструкторе предотвратит выполнение оставшихся подпрограмм завершения работы.