Подтвердить что ты не робот

PHP [OOP] - Как вызвать конструктор классов вручную?

Пожалуйста, смотрите ниже:

01. class Test {
02.     public function __construct($param1, $param2, $param3) {
03.         echo $param1.$param2.$param3;
04.     }
05. }
06. 
07. $params = array('p1','p2','p3');
08. 
09. $ob = new Test;
10. 
11. if(method_exists($ob,'__construct')) {
12.     call_user_func_array(array($ob,'__construct'),$params);
13. }

Теперь проблема заключается в конструкторе в строке 09

Но я хочу называть его вручную в строке 11-13

Возможно ли это? Если тогда как? Любая идея пожалуйста?

4b9b3361

Ответ 1

Невозможно предотвратить вызов конструктора при построении объекта (строка 9 в вашем коде). Если в вашем методе __construct() есть какая-то функциональность, которую вы хотите отложить до завершения строительства, вы должны перенести ее на другой метод. Хорошим именем для этого метода может быть init().

Почему бы просто не сделать это?

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }
}

$ob = new Test('p1', 'p2', 'p3');

EDIT: Я просто подумал о хакерском способе, которым вы могли бы запретить вызов конструктора (вроде). Вы можете подклассифицировать Test и переопределить конструктор с помощью пустого конструктора do-nothing.

class SubTest extends Test {
    public function __construct() {
        // don't call parent::__construct()
    }

    public function init($param1, $param2, $param3) {
        parent::__construct($param1, $param2, $param3);
    }
}

$ob = new SubTest();
$ob->init('p1', 'p2', 'p3');

Это может иметь смысл, если вы имеете дело с каким-то кодом, который по какой-то причине вам не по каким-либо причинам, и вам нужно обойти некоторое раздражающее поведение плохо написанного конструктора.

Ответ 2

Обратите внимание, что если конструктор (метод __construct) содержит аргументы, переданные ссылку, то функция:

call_user_func_array

завершится с ошибкой.

Я предлагаю вам вместо этого использовать класс Reflection; вот как вы можете это сделать:

// assuming that class file is already included.

$refMethod = new ReflectionMethod('class_name_here',  '__construct');
$params = $refMethod->getParameters();

$re_args = array();

foreach($params as $key => $param)
{
    if ($param->isPassedByReference())
    {
        $re_args[$key] = &$args[$key];
    }
    else
    {
        $re_args[$key] = $args[$key];
    }
}

$refClass = new ReflectionClass('class_name_here');
$class_instance = $refClass->newInstanceArgs((array) $re_args);

Ответ 3

Если разделение экземпляра от инициализации не является строго требованием, есть еще две возможности: во-первых, статический метод factory.

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }

    public static function CreateTest($param1, $param2, $param3) {
        return new Test($param1, $param2, $param3);
    }
}

$params = array('p1','p2','p3');

if(method_exists($ob,'__construct')) {
    call_user_func_array(array($ob,'CreateTest'),$params);
}

Или, если вы используете php 5.3.0 или выше, вы можете использовать lambda:

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }
}

$params = array('p1','p2','p3');

$func = function ($arg1, $arg2, $arg3) {
    return new Test($arg1, $arg2, $arg3);
}

if(method_exists($ob,'__construct')) {
    call_user_func_array($func, $params);
}

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

Метод factory хорош, потому что он дает вам метод вызова, чтобы получить инициализированный экземпляр. Объект инициализируется и создается в той же операции, поэтому, если вам нужно отделить два, это не сработает.

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

Ответ 4

Я не знаю, есть ли проблемы с безопасностью, используя метод eval(), но вы можете сделать себе такую ​​функцию:

function CreateObj($className,$params)
{
    $strArgs = '$params['.implode('],$params[',array_keys($params)).']';
    eval('$ob = new '.$className.'('.$strArgs.');');
    return $ob
}

И теперь $ob теперь должен быть определен с его правильными параметрами, я его не тестировал и, возможно, в коде есть ошибка, но вы получаете идею....

Ответ 5

сначала создать свой объект, а затем передать параметры, которые вы могли бы попробовать таким образом:

class Test {
    public function __CONSTRUCT($p1="Bundy", $p2="house", $p3=10) {
        $this->init($p1, $p2, $p3);
    }
    public function init($p1, $p2, $p3) {
        //setup your object here
    }
}

то можно построить объект и вызвать

$ob->init($p1, $p2, $p3);

позже.

Ответ 6

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

Затем конструктор можно вызвать вручную.

Обычно это не требуется. Смотрите также: Загрузка объекта из сеанса PHP, вызывает ли он конструктор?

<?php

class Test
{
    public function __construct()
    {
        echo '__construct called.',"\n";
    }
}

function old($class)
{
    return unserialize
    (
        sprintf
        (
            'O:%d:"%s":0:{}', 
            strlen($class), 
            $class
        )
    );
}

$test = old('Test');
$test->__construct();