Doctrine nevolá konstruktor u entity

Pro mnohé z vás to pravděpodobně nebude novinka, ale pro mě to byl chvíli WTF moment, nad kterým jsem nějakou dobu zaměstnal svůj mozek.

Než se dostanu přímo k Doctrine, na chvíli odbočím.

Při hledání důvodu, proč jej nevolá, jsem narazil na další zajímavou věc, která s tím souvisí: Funkce unserialize totiž nevolá konstruktor.

Ono to dává logicky smysl, protože stav objektu je při serializaci uložen a nemá být voláno nic. Informace o tomto chování je navíc i v dokumentaci.

Na ukázku chování mám tento kód:

<?php

class MujObject {
    private $test = 1;
    
    public function __construct()
    {
        $this->test = 2;
    }
}

$array = unserialize('O:9:"MujObject":0:{}');
var_dump($array);

/*
object(MujObject)#1 (1) {
  ["test":"MujObject":private]=>
  int(1)
}
*/

$array = new MujObject();
var_dump($array);

/*
object(MujObject)#2 (1) {
  ["test":"MujObject":private]=>
  int(2)
}
*/

Entity samozřejmě Doctrine neukládá serializované, aby je poté deserializovala, ale záměrně se konstruktoru vyhýbá, aby jste jej mohli ve svém kódu s libovolnými parametry použít.

Doctrine tak při vytahování dat z databáze neinicializuje entitu přes volání „new“, ale používá unserialize a nověji už ReflectionClass::newInstanceWithoutConstructor.

https://github.com/doctrine/instantiator/blob/master/src/Doctrine/Instantiator/Instantiator.php#L86

Samotná dokumentace toto zmiňuje: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/architecture.html

„The constructor of an entity is only ever invoked when you construct a new instance with the new keyword. Doctrine never calls entity constructors, thus you are free to use them as you wish and even have it require arguments of any type.“

Pokud v entitě při použití Doctrine potřebuje zavolat kód, který byste běžně dali jen do konstruktoru, musíte použít event @postLoad.

Sdílením článku mi pomůžete a uděláte mi velikou radost :)

Komentáře