2012-01-17 21 views
11

Tengo un conjunto de clases que extienden una clase abstracta. La clase abstracta contiene métodos que hacen uso de enlaces estáticos tardíos para obtener información que se define en las clases secundarias. Así, por ejemplo, la clase abstracta puede tener un método que contiene la línea:PHP - Forzar una clase para declarar una propiedad

$var = static::$childVar . ' some text'; 

De esta manera, es posible en tiempo de ejecución para el método definido en la clase abstracta para generar diferentes cadenas en función del valor de una variable definido en las clases de niños.

Lo que quiero hacer es tener algún mecanismo que obligue a las clases secundarias a declarar esta variable, eliminando la posibilidad de que se llame al método si la variable no está configurada.

Usando interfaces, es posible requerir una clase para definir métodos (y constantes, que lamentablemente no pueden tener su visibilidad modificada usando public/protected/private). Entonces, si una clase implementa una interfaz, pero no define todos los métodos especificados en la interfaz, se genera un error. Sin embargo, no hay forma de usar una interfaz para requerir que una clase defina una propiedad.

He visto algún material que sugiere usar métodos getter en la interfaz (por ejemplo, getChildVar()) para exigir implícitamente declaración de variables, pero esto no es adecuado para mí ya que no quiero que las variables sean accesibles fuera de la clase (tienen visibilidad protected).

Del mismo modo, las constantes no funcionarán, porque no son compatibles con el modificador de visibilidad protected.

Sé que siempre podría usar una declaración isset() para verificar esto en el método (o incluso en el constructor) de la clase abstracta, pero esto parece poco elegante en comparación con el uso de interfaces para asegurar que se definan los métodos. Me pregunto si hay alguna forma estándar de hacerlo sin tener que codificar los requisitos en mi clase abstracta.

Por cierto, si alguien sabe por qué no puede declarar variables dentro de las interfaces, me interesaría saber cuál es el razonamiento. Me parece un gran descuido.

Cualquier ayuda será muy apreciada.

Respuesta

10

No puede imponer variables en una interfaz porque una interfaz es una representación pública de cómo usar su clase. Si soy otro desarrollador que se une a su proyecto, quiero poder ver la interfaz y saber que todos los métodos que puedo asumir se implementan en clases que, bueno, implementan esa interfaz. Esto no es tan relevante para propiedades privadas o protegidas, o realmente ninguna propiedad específica para el caso. Getters/setters son el estándar para ese tipo de cosas.

El descuido en este momento es que no se puede tener un método mágico para tratar de acceder a una propiedad estática indefinida. Esa sería la solución ideal para usted aquí.

Si la propiedad estática se declara en tiempo de ejecución, ¿por qué no aplicar un método setChildVar() o poner un método de clase padre que obtiene la propiedad static-bound y genera un error si no está configurado? Incluso podría implementar un patrón de "controlador" para lograr esto:

<?php 

class MyParentClass { 

    public function __get($key) 
    { 
     if (!isset(static::$$key)) 
     { 
      throw new Exception('Child class '.get_called_class().' failed to define static '.$key.' property'); 
     } 

     return static::$$key; 
    } 

    public function getText() 
    { 
     return $this->childVar . ' some text'; 
    } 

} 

class MyChildClass extends MyParentClass { 

    protected static $childVar = 'some value:'; 

} 

$a = new MyChildClass; 
echo $a->getText(); // some value: some text 
+0

Gracias por esta explicación. Ahora entiendo por qué las interfaces no permiten la declaración de variables (aunque no estoy seguro de estar completamente de acuerdo con el razonamiento detrás de esa decisión). Y de hecho, me encontré con casi línea por línea exactamente el mismo código que tienes aquí, así que es bueno saber que lo estoy haciendo bien. – C106

Cuestiones relacionadas