ejemplos - que es un constructor en php
¿Cómo puedo obtener un constructor de clases PHP para llamar al constructor padre de sus padres? (15)
Necesito tener un constructor de clases en PHP para llamar al constructor padre de los padres (¿abuelo?) Sin llamar al constructor padre.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA''S
// CONSTRUCTOR AND NOT PAPA''S
}
}
Sé que esto es algo extraño de hacer y estoy tratando de encontrar un medio que no huela mal pero, sin embargo, tengo curiosidad si es posible.
EDITAR
Pensé que debería publicar la justificación de la respuesta elegida. La razón es; es la solución más elegante para el problema de querer llamar al constructor de "abuelos" mientras se conservan todos los valores. Ciertamente no es el mejor enfoque ni es amigable con OOP, pero eso no es lo que la pregunta estaba haciendo.
Para cualquier persona que se encuentre con esta pregunta en una fecha posterior, encuentre otra solución . Pude encontrar un enfoque mucho mejor que no causó estragos en la estructura de clases. Por lo que debería.
Debes usar Grandpa::__construct()
, no hay otro atajo para eso. Además, esto arruina la encapsulación de la clase Papa
: al leer o trabajar con Papa
, debería ser seguro suponer que se __construct()
método __construct()
durante la construcción, pero la clase Kiddo
no lo hace.
Detalles graciosos sobre php: las clases extendidas pueden usar funciones no estáticas de una clase padre en una materia estática. Afuera obtendrás un error estricto.
error_reporting(E_ALL);
class GrandPa
{
public function __construct()
{
print("construct grandpa<br/>");
$this->grandPaFkt();
}
protected function grandPaFkt(){
print(">>do Grandpa<br/>");
}
}
class Pa extends GrandPa
{
public function __construct()
{ parent::__construct();
print("construct Pa <br/>");
}
public function paFkt(){
print(">>do Pa <br>");
}
}
class Child extends Pa
{
public function __construct()
{
GrandPa::__construct();
Pa::paFkt();//allright
//parent::__construct();//whatever you want
print("construct Child<br/>");
}
}
$test=new Child();
$test::paFkt();//strict error
Entonces, dentro de una clase extendida (Niño) puede usar
parent::paFkt();
o
Pa::paFkt();
para acceder a la función de un padre (o abuelo) (no privado).
Afuera de clase def
$test::paFkt();
tendrá un error estricto (función no estática).
Estoy de acuerdo con "demasiado php", prueba esto:
class Grandpa
{
public function __construct()
{
echo ''Grandpa<br/>'';
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo ''Papa<br/>'';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA''S
// CONSTRUCTOR AND NOT PAPA''S
echo ''Kiddo<br/>'';
Grandpa::__construct();
}
}
$instance = new Kiddo;
Obtuve el resultado como esperaba:
Kiddo
Abuelo
Esta es una característica, no un error, verifique esto para su referencia:
Es solo la forma en que funciona. Si ve que viene del contexto correcto, esta versión de llamada no aplica una llamada estática.
En cambio, simplemente mantendrá $ this y será feliz con eso.
parent :: method () funciona de la misma manera, no tiene que definir el método como estático, pero puede invocarse en el mismo contexto. Prueba esto para ser más interesante:
class Grandpa
{
public function __construct()
{
echo ''Grandpa<br/>'';
Kiddo::hello();
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo ''Papa<br/>'';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA''S
// CONSTRUCTOR AND NOT PAPA''S
echo ''Kiddo<br/>'';
Grandpa::__construct();
}
public function hello()
{
echo ''Hello<br/>'';
}
}
$instance = new Kiddo;
También funciona como se esperaba:
Kiddo
Abuelo
Hola
Pero si intentas inicializar un nuevo Papa, obtendrás un error de E_STRICT:
$papa = new Papa;
Estándares estrictos: Método no estático Kiddo :: hello () no debe llamarse estáticamente, suponiendo $ this desde un contexto incompatible
Puede usar instanceof para determinar si puede llamar a un método Children :: () en un método principal:
if ($this instanceof Kiddo) Kiddo::hello();
Hay una solución más fácil para esto, pero requiere que sepa exactamente cuánta herencia ha pasado su clase actual. Afortunadamente, los argumentos de get_parent_class () permiten que el miembro de la matriz de la clase sea el nombre de la clase como una cadena, así como una instancia en sí misma.
Tenga en cuenta que esto también se basa intrínsecamente en llamar estáticamente a un método de clase __construct (), aunque dentro del alcance instanciado de un objeto heredado, la diferencia en este caso particular es insignificante (ah, PHP).
Considera lo siguiente:
class Foo {
var $f = ''bad (Foo)'';
function __construct() {
$this->f = ''Good!'';
}
}
class Bar extends Foo {
var $f = ''bad (Bar)'';
}
class FooBar extends Bar {
var $f = ''bad (FooBar)'';
function __construct() {
# FooBar constructor logic here
call_user_func(array(get_parent_class(get_parent_class($this)), ''__construct''));
}
}
$foo = new FooBar();
echo $foo->f; #=> ''Good!''
De nuevo, esta no es una solución viable para una situación en la que no tienes idea de cuánta herencia ha tenido lugar, debido a las limitaciones de debug_backtrace (), pero en circunstancias controladas, funciona como se esperaba.
Hermosa solución usando Reflection
.
<?php
class Grandpa
{
public function __construct()
{
echo "Grandpa''s constructor called/n";
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo "Papa''s constructor called/n";
// call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
echo "Kiddo''s constructor called/n";
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), ''__construct'');
$reflectionMethod->invoke($this);
}
}
$kiddo = new Kiddo();
$papa = new Papa();
La fea solución sería pasarle un parámetro booleano a Papa indicando que no desea analizar el código contenido en el constructor. es decir:
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct($bypass = false)
{
// only perform actions inside if not bypassing
if (!$bypass) {
}
// call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
$bypassPapa = true;
parent::__construct($bypassPapa);
}
}
Ok, otra solución fea:
Crea una función en Papa como:
protected function call2Granpa() {
return parent::__construct();
}
Luego en Kiddo usas:
parent::call2Granpa();
// en lugar de llamar al constructor en Papa.
Creo que podría funcionar ... No lo he probado, así que no estoy seguro de si los objetos se crearon correctamente.
Usé este enfoque pero con funciones que no son de constructor.
Otra opción que no utiliza una bandera y podría funcionar en su situación:
<?php
// main class that everything inherits
class Grandpa
{
public function __construct(){
$this->GrandpaSetup();
}
public function GrandpaSetup(){
$this->prop1 = ''foo'';
$this->prop2 = ''bar'';
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa''s constructor
parent::__construct();
$this->prop1 = ''foobar'';
}
}
class Kiddo extends Papa
{
public function __construct()
{
$this->GrandpaSetup();
}
}
$kid = new Kiddo();
echo "{$kid->prop1}/n{$kid->prop2}/n";
Puedes llamar a Grandpa :: __build desde donde quieras y $ $ esta palabra clave se referirá a tu instancia de clase actual. Pero tenga cuidado con este método; no puede acceder a propiedades y métodos protegidos de la instancia actual desde este otro contexto, solo a elementos públicos. => Todo el trabajo y link .
Ejemplo
// main class that everything inherits
class Grandpa
{
public function __construct()
{
echo $this->one; // will print 1
echo $this->two; // error cannot access protected property
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public $one = 1;
protected $two = 2;
public function __construct()
{
Grandpa::__construct();
}
}
new Kiddo();
Terminé encontrando una solución alternativa que resolvió el problema.
- Creé una clase intermedia que amplió al abuelo.
- Entonces, tanto papá como Kiddo extendieron esa clase.
- Kiddo requirió algunas funcionalidades intermedias de Papa, pero no le gustó su constructor, por lo que la clase tiene esa funcionalidad adicional y ambas la amplían.
He actualizado las otras dos respuestas que dieron soluciones válidas pero feas para una pregunta más fea :)
de php 7 puedes usar
parent::parent::__construct();
class Grandpa
{
public function __construct()
{
echo"Hello Kiddo";
}
}
class Papa extends Grandpa
{
public function __construct()
{
}
public function CallGranddad()
{
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
}
public function needSomethingFromGrandDad
{
parent::CallGranddad();
}
}
<?php
class grand_pa
{
public function __construct()
{
echo "Hey I am Grand Pa <br>";
}
}
class pa_pa extends grand_pa
{
// no need for construct here unless you want to do something specifically within this class as init stuff
// the construct for this class will be inherited from the parent.
}
class kiddo extends pa_pa
{
public function __construct()
{
parent::__construct();
echo "Hey I am a child <br>";
}
}
new kiddo();
?>
Por supuesto, esto espera que no necesites hacer nada dentro del constructo de la pa_pa. Al ejecutar esto se generará:
Hola, soy Grand Pa Hey, soy un niño
// main class that everything inherits
class Grandpa
{
public function __construct()
{
$this->___construct();
}
protected function ___construct()
{
// grandpa''s logic
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
parent::___construct();
}
}
tenga en cuenta que "___construct" no es un nombre mágico, puede llamarlo "doGrandpaStuff".
class Grandpa
{
public function __construct()
{}
}
class Papa extends Grandpa
{
public function __construct()
{
//call Grandpa''s constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
//this is not a bug, it works that way in php
Grandpa::__construct();
}
}