См. Ниже код:
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();