2009-12-14 11 views
11

Por favor ver el código abajo:PHP [OOP] - ¿Cómo llamar al constructor de clase manualmente?

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. } 

Ahora, el problema es el constructor de que se llama en la línea 09

pero quiero llamarlo manualmente en la línea 11-13

¿Es posible? Entonces, ¿cómo? Cualquier idea por favor?

+0

tenga en cuenta que si los parámetros del constructor son pasados ​​por referencia, entonces call_user_func_array fallará !! – Sarfraz

Respuesta

21

No es posible evitar que se llame al constructor cuando se construye el objeto (línea 9 en su código). Si hay alguna funcionalidad que ocurra en su método __construct() que desea posponer hasta después de la construcción, debe moverla a otro método. Un buen nombre para ese método podría ser init().

¿Por qué no hacer esto?

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

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

EDIT: Acabo de pensar de una manera hacky que podría evitar que un constructor sea llamado (más o menos). Puede subclase Test y anular el constructor con un constructor vacío, 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'); 

Ésta es podría tener sentido si usted está tratando con un código que no se puede cambiar por alguna razón y la necesidad de evitar un comportamiento molesto de un constructor mal escrito.

0

para construir el objeto primero y luego pasar parámetros a su podría tratar de esta manera:

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 
    } 
} 

entonces es posible construir el objeto y llamar

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

más tarde.

+2

Esto no funciona porque PHP no admite la sobrecarga de métodos. Esta estrategia funcionaría en un lenguaje como Java. – Asaph

+0

Sí, tienes razón. Eliminé la sobrecarga del constructor ... ... hice demasiada java últimamente – justastefan

+0

Ok, buena edición pero tu '$ ob-> init ($ params);' no se ve coherente con tu definición de la función 'init()' que acepta 3 argumentos en lugar de una única matriz. Por cierto: no existe tal cosa como Java. – Asaph

1

Si separar instancias de la inicialización no es estrictamente un requisito, existen otras dos posibilidades: primero, un método de fábrica estático.

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

O, si usted está usando PHP 5.3.0 o superior, se puede utilizar un 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); 
} 

El método de inicialización descrito por Asaf es grande si por alguna razón usted tiene una necesidad para separar lógicamente la inicialización de la creación de instancias, pero si respaldar su caso de uso anterior es un caso especial, no un requisito regular, puede ser inconveniente solicitar a los usuarios que creen e inicialicen su objeto en dos pasos separados.

El método de fábrica es bueno porque le da un método para llamar para obtener una instancia inicializada. Sin embargo, el objeto se inicializa y crea una instancia en la misma operación, por lo que si necesita separar los dos, no funcionará.

Y, por último, recomiendo la lambda si este mecanismo de inicialización se utiliza de forma poco común, y no quiere complicar la definición de clase con métodos de inicialización o de fábrica que casi nunca se utilizarán.

9

Observe que si el constructor (método __construct) contiene argumentos pasados ​​por de referencia, entonces la función:

call_user_func_array 

fallará con un error.

Le sugiero que use la clase Reflection en su lugar; aquí es cómo puedes hacerlo:

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

En PHP puedes crear objetos sin llamar al constructor. Pero eso no funciona al usar un nuevo objeto, sino al no serializarlo.

El constructor se puede llamar manualmente.

Normalmente esto no es necesario. Ver también: Loading an object from PHP session, does it call constructor?

<?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(); 
1

no sé si hay algunas preocupaciones de seguridad mediante el método eval(), pero se le podría caer una función como esta:

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

Y ahora $ ob ahora debe definirse con sus parámetros correctos, no lo he probado y tal vez haya un error en el código, pero se entiende ...

Cuestiones relacionadas