2010-03-31 16 views
15

De todos modos, ¿es posible crear una instancia de una clase php sin llamar a su constructor?En PHP, ¿es posible crear una instancia de una clase sin llamar al constructor de la clase?

Tengo la Clase A y al crear una instancia de la misma paso un archivo y en el constructor de la Clase A abro el archivo.

Ahora en la clase A, hay una función que necesito llamar pero no estoy obligado a pasar el archivo y no es necesario usar la funcionalidad del constructor de abrir el archivo como no estoy pasando el archivo.

Así que mi pregunta es, ¿es posible de alguna manera crear una instancia de una clase PHP sin llamar a su constructor?

Nota No puedo hacer la función estática ya que estoy usando algunas de las propiedades de clase en la función.

Respuesta

12

Un constructor de clases siempre se llamará. Sin embargo, hay un par de formas en que podrías evitar esto.

La primera forma es proporcionar valores predeterminados para sus parámetros en el constructor, y solo realizar ciertas acciones en esos parámetros si están configurados. Por ejemplo:

class MyClass { 
    public __construct($file = null) { 
     if ($file) { 
      // perform whatever actions need to be done when $file IS set 
     } else { 
      // perform whatever actions need to be done when $file IS NOT set 
     } 
     // perform whatever actions need to be done regardless of $file being set 
    } 
} 

Otra opción es extender la clase de tal manera que el constructor de la clase hija no llama al constructor de la clase padre.

class MyParentClass { 
    public __construct($file) { 
     // perform whatever actions need to be done regardless of $file being set 
    } 
} 

class MyChildClass extends MyParentClass { 
    public __construct() { 
     // perform whatever actions need to be done when $file IS NOT set 
    } 
} 
+1

O, como han señalado otros, un método estático puede adaptarse mejor a sus necesidades dependiendo de lo que esté tratando de hacer. –

+1

+1 para extender la clase. Tal vez es una clase de una biblioteca de terceros que no debe cambiarse ... –

+0

+1 para las buenas soluciones alternativas. – Yacoby

2

¿No sería mejor hacer la función que necesita static - alterar la clase A de modo que tenga otro constructor que no toma ningún aruguments


Si una clase tiene una función que doesn Para acceder a cualquiera de las propiedades o funciones no estáticas en una clase, puede estar estático.

class A{ 
    public function __construct($arg1){ 
    } 

    public static function foo(){ 
     //do something that doesn't involve the class properties 
    } 
} 

A continuación, se puede llamar sin tener que construir la clase

//the constructor will not be called as we haven't created an instance of A 
A::foo(); 

La diferencia entre una estática y una función estática ninguno es que la función estática no puede acceder a las propiedades de clase de funciones que también son estáticas . Entonces, si en foo() tiene un código que usa $this->, no puede hacerlo estático.

+0

realmente apreciaría si puede usted explicar más en esto como no lo tengo claro. – Rachel

+0

Ahora, ¿cuál es la diferencia al llamar a 'A-> foo() frente a A :: foo()' – Rachel

+1

@Rachel: Llamarías a '$ a-> foo()' como método de una instancia y 'A :: foo() 'como un método de clase estático.Este último no ** funciona ** en instancias de la clase 'A' y, por lo tanto, no tiene que llamar' nuevo A() 'para crear uno. Para obtener una mejor idea, puede leer este artículo: http://en.wikipedia.org/wiki/Static_methods y el documento PHP: http://www.php.net/manual/en/language.oop5.static .php –

-1

puede hacer que el método sea estático y llamarlo desde el contexto de la clase y no desde el contexto del objeto.

en el código se vería así:

class A { 
    public static function func($txt) { 
    print($txt); 
    } 
} 

A::func('test'); 
+0

Hmm, cómo esto se puede hacer, realmente no estoy seguro. Agradecería si puede dar más explicaciones al respecto. – Rachel

13

Nota: La solución a continuación es para PHP 5.3 y por debajo. A partir de PHP 5.4, también puede do it via Reflection as shown elsewhere on this page.

Esto es realmente posible.

Modificado de PHPUnit_Framework_MockObject_Generator

1 $myClass = unserialize(
2  sprintf(
3   'O:%d:"%s":0:{}', 
4   strlen('MyClass'), 'MyClass' 
5  ) 
6 ); 

Por favor, tenga en cuenta, que un código como todo esto es bueno y justificado en un marco como PHPUnit. Pero si debe tener un código como este en su código de producción, es probable que esté haciendo algo muy extraño.


Has solicitado que una explicación:

Cuando serialize an Object se obtiene una representación de cadena del objeto. Por ejemplo

echo serialize(new StdClass) // gives O:8:"stdClass":0:{} 

El objeto O significa. 8 es la longitud de cadena del nombre de clase. "stdClass" es obviamente el nombre de clase. El objeto serializado tiene 0 conjunto de propiedades (más que el posterior), indicado por las llaves vacías. : son solo delimitadores.

Cada cadena serializada se puede recrear en su valor "directo" original con la función unserialize. Al hacerlo, sorteará al constructor. Como Charles señaló correctamente, se llamará al magic method __wakeup() si está definido (al igual que se llamará __sleep() al serializar).

En la línea 3 verá una cuerda preparada para ser utilizada con sprintf (línea 2). Como puede ver, la longitud de la cadena del nombre de la clase se da como %d y el nombre de la clase se da como %s. Esto es para indicarle a sprintf que debe usar el primer argumento que se le pasa en la línea 4 como un dígito y el segundo como una cadena. Por lo tanto, el resultado de la llamada sprintf es

'O:7:"MyClass":0:{}' 

debería reemplazar ambas ocurrencias de "MyClass" en la línea 4 con su nombre de la clase deseada para crear una cadena en serie de la clase en la que desea crear una instancia sin necesidad de invocar el controlador.

Esta cadena se deserializa en una instancia de MyClass en la línea 1, sin pasar por el constructor. La instancia no serializada tendrá todos los métodos de su clase y también cualquier propiedad. Si hay propiedades en MyClass, éstas tendrán sus valores predeterminados, a menos que agregue valores diferentes a la cadena ficticia serializada.

Y eso ya es todo. Nada demasiado mágico al respecto.

+0

Esto es muy difícil de entender. ¿Puedes agregarle alguna explicación? – Rachel

+1

Este código crea manualmente una representación serializada de la clase, luego la desercializa. Esto crea una nueva copia del objeto sin llamar al constructor. Sin embargo, intentará llamar al método __wakeup(). – Charles

+0

@Rachel @Charles hizo un buen trabajo al resumirlo, pero también veré mi explicación detallada. – Gordon

17

En su caso, le recomendaría pensar en rediseñar su código para que no tenga que hacer tales cosas, sino para responder su pregunta: sí, es posible.

Puede utilizar ReflectionClass y es el método newInstanceWithoutConstructor introducido en PHP 5.4 Entonces es muy fácil crear una instancia de una clase sin llamar a su constructor:

$reflection = new ReflectionClass("ClassName"); 
$instance = $reflection->newInstanceWithoutConstructor(); //That's it! 
+3

No vale la pena que 'newInstanceWithoutConstructor()' esté disponible con PHP 5.4.0. No está disponible en ninguna versión de PHP 5.3 o inferior. – salathe

+0

Gracias por la información. La documentación de PHP me engañó ... –

Cuestiones relacionadas