PHP – Как вызвать конструктор классов вручную?

См. Ниже код:

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

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

Невозможно предотвратить вызов конструктора при построении объекта (строка 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'); 

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

Обратите внимание: если конструктор (метод __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); 

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

 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 или выше, вы можете использовать лямбда:

 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, велик, если по какой-то причине вам необходимо логически отделять инициализацию от экземпляра, но если поддержка вашего примера использования выше – это особый случай, а не регулярное требование, может быть неудобно требовать от пользователей экземпляра и инициализируйте свой объект двумя разными шагами.

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

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

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

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

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

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

 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); 

позже.

В 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();