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
это возможно? Если да, то как? Любой идея пожалуйста?
6 ответов
невозможно предотвратить вызов конструктора при построении объекта (строка 9 в коде). Если есть какая-то функциональность, которая происходит в вашем __construct()
метод, который вы хотите отложить до окончания строительства, вы должны переместить его в другой метод. Хорошим названием для этого метода может быть init()
.
почему бы просто не сделать это?
class Test {
public function __construct($param1, $param2, $param3) {
echo $param1.$param2.$param3;
}
}
$ob = new Test('p1', 'p2', 'p3');
EDIT: я просто подумал о хакерском способе, которым вы могли бы предотвратить вызов конструктора (вроде). Вы можете подкласс Test
и переопределить конструктор пустым конструктором ничего не делать.
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
завершается с ошибкой.
Я предлагаю вам вместо этого использовать класс отражения; вот как вы можете это сделать:
// 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 вы можете создавать объекты без вызова конструктора. Но это не работает с помощью new, а путем отмены сериализации экземпляра объекта.
конструктор можно вызвать вручную.
обычно это не требуется. Смотрите также: загрузка объекта из сеанса 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();