Рекурсивные зависимости

210
02 июля 2017, 15:57
class ClassA {
    function __construct(ClassB $paramB) {
    }
}
class ClassB {
    function __construct(ClassA $paramA) {
    } 
}

Вопрос: как можно решить данную зависимость чтобы в результате выполнения было только 2 объекта без промежуточных или по другому чтобы в стеке вызова было только 2 этих конструктора.

Answer 1

Пропущу лекцию, почему так писать код нельзя, что сделать с архитектором такое сделавшим и сразу тогда уж напишу, как всё-таки выкрутиться можно.

Самое простое и читерское - через механизм Reflection.

$r = new ReflectionClass('ClassA');
$a = $r->newInstanceWithoutConstructor();
$b = new ClassB($a);
$a->__construct($b);

ReflectionClass::newInstanceWithoutConstructor доступен начиная с PHP 5.4 и позволяет получить объект класса без вызова конструктора. Разумеется, класс в этом случае может быть неработоспособным. В то же время конструктор является обычным методом класса, который возможно вызвать.

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

Больше мороки, но так же возможно сделать через механизм сериализации. Результат serialize - строка. unserialize может восстановить объект. Строку же можно составить самостоятельно, зная как объекты сериализуются. Пример в комментариях к мануалу есть (процитирую для полноты ответа):

function createInstanceWithoutConstructor($class){
    $reflector = new ReflectionClass($class);
    $properties = $reflector->getProperties();
    $defaults = $reflector->getDefaultProperties();
    $serealized = "O:" . strlen($class) . ":\"$class\":".count($properties) .':{';
    foreach ($properties as $property){
        $name = $property->getName();
        if($property->isProtected()){
                $name = chr(0) . '*' .chr(0) .$name;
            } elseif($property->isPrivate()){
                $name = chr(0)  . $class.  chr(0).$name;
            }
            $serealized .= serialize($name);
            if(array_key_exists($property->getName(),$defaults) ){
                $serealized .= serialize($defaults[$property->getName()]);
            } else {
                $serealized .= serialize(null);
            }
        }
    $serealized .="}";
    return unserialize($serealized);
}

С корректировкой кода, вероятно, даже в PHP4 получится создать объект. Но не все классы возможно сериализовать и, соответственно, распаковать обратно.

READ ALSO
вывод кириллицы в php через cron

вывод кириллицы в php через cron

Есть php файл, в нем прописано:

182
Шаблоны в Yii2 - как пользоваться?

Шаблоны в Yii2 - как пользоваться?

Сразу прошу прощения, если глупый вопрос, но я так и не понял, есть ли такое в yii2, и если есть - то как им пользоватьсяЧто я имею ввиду: есть такой...

387