2009-02-10 22 views
27

en PHP, si un atributo estático se define en la clase padre, no puede ser anulado en una clase de niños. Pero me pregunto si hay alguna forma de evitar esto.La herencia de los miembros estáticos en PHP

Estoy intentando escribir un envoltorio para la función de otra persona (un poco anticuado). La función en cuestión se puede aplicar a muchos tipos de datos diferentes, pero requiere diferentes indicadores y opciones para cada uno. Pero el 99% del tiempo, un valor por defecto para cada tipo sería suficiente.

Sería bueno si esto se podría hacer con la herencia, sin tener que escribir nuevas funciones cada vez. Por ejemplo:

class Foo { 
    public static $default = 'DEFAULT'; 

    public static function doSomething ($param = FALSE) { 
     $param = ($param === FALSE) ? self::$default : $param; 
     return $param; 
    } 
} 

class Bar extends Foo { 
    public static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
} 

echo Foo::doSomething() . "\n"; 
// echoes 'DEFAULT' 

echo Bar::doSomething() . "\n"; 
// echoes 'DEFAULT' not 'NEW DEFAULT FOR CHILD CLASS' 
// because it references $default in the parent class :(

Respuesta

15

ejemplo clásico de por qué el uso de la estática como globales (funciones en este caso) es una mala idea, sin importar el idioma.

El método más robusto es crear múltiples clases de implementación de un sub clase base abstracta "Acción".

A continuación, para tratar de eliminar algunas de la molestia de crear instancias de una instancia de la clase sólo para llamar Es métodos, se puede envolver en una fábrica de algún tipo.

Por ejemplo:

abstract class AbstractAction { 
    public abstract function do(); 
} 

class FooAction extends AbstractAction { 
    public function do() { 
    echo "Do Foo Action"; 
    } 
} 

class BarAction extends AbstractAction { 
    public function do() { 
    echo "Do Bar Action"; 
    } 
} 

A continuación, cree una fábrica de "ayuda" en la creación de instancias de la función

class ActionFactory { 
    public static function get($action_name) { 
    //... return AbstractAction instance here 
    } 
} 

luego usarlo como:

ActionFactory::get('foo')->do(); 
27

La próxima versión de PHP 5.3.0 incluye late static binding, lo que podría ayudar. Usando esta característica, puede usar una variable estática dentro de un método estático y dejar que el enlace estático tardío se encargue de encontrar el método "correcto".

class Foo { 
    public static function getDefault() { 
     static $default = 'DEFAULT'; 
     return $default; 
    } 
    public static function doSomething ($param) { 
     $default=static::getDefault(); // here is the late static binding 
     $param = ($param === FALSE) ? $default : $param; 
     return $param; 

    } 
} 

class Bar extends Foo { 
    public static function getDefault() { 
     static $default = 'NEW DEFAULT FOR CHILD CLASS'; 
     return $default; 
    } 
} 
+1

Esto sería encantador y gracias por la información. Pero, por desgracia, necesito algo que funcione en mi entorno de producción actual (5.2.6). ¡GRACIAS! – PartialOrder

24

En realidad creo que no es cierto: puede evitar las propiedades estáticas () que necesita> = 5.3 PHP para eso). Pero hay que tener cuidado cuando refrencing para esa propiedad estática (y este es el error en el código original)

Es necesario utilizar estática :: $ myStaticProperty en lugar de utilizar self :: $ myStaticProperty

self :: se refrence a la clase actual por lo que si usted está dentro de un método estático heredado esto refrence la propiedad estática de esa clase definida de ese método! Al usar la palabra clave de referencia static :: se comportará como $ this - cuando se utilizan métodos de ejemplo/propeties.

doSomething() es un método estático heredado en la clase Bar en su ejemplo. Como utilizó self :: there, hará referencia a la propiedad estática de la clase Foo. Esta es la razón por la que no vio ninguna diferencia ... Intenta cambiar self :: to static ::!

Aquí hay un ejemplo de código: lo usé yo mismo para probar esas cosas. Tenemos propiedad estática/herencia de método, anulación y cambio de valor en él - ¡ejecútelo y verá el resultado!

class A { 

    // a static property - we will test override with it 
    protected static $var = 'class A var - override'; 
    // a static property - we will test value overwrite with it 
    protected static $var2 = 'class A var2 - value overwrite'; 


    public static function myStaticOverridePropertyTest() { 
     return static::$var; 
    } 
    public static function myStaticValueOverwritePropertyTest() { 
     return static::$var2; 
    } 

    /** 
    * This method is defined only here - class B will inherit this one! 
    * We use it to test the difference btw self:: and static:: 
    * 
    * @return string 
    */ 
    public static function myStaticMethodTest() { 
     //return self::getValue(); 
     return static::getValue(); 
    } 

    /** 
    * This method will be overwritten in class B 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class A'; 
    } 
} 


class B extends A { 

    // we override this inherited static property 
    protected static $var = 'class B var - override'; 

    /** 
    * This method is overwritten from class A 
    * @return string 
    */ 
    protected static function getValue() { 
     return 'value from class B'; 
    } 

    /** 
    * We modify the value of the inherited $var2 static property 
    */ 
    public static function modStaticProperty() { 
     self::$var2 = 'class B - altered value! - value overwrite'; 
    } 
} 

echo ("-- testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

echo ("-- now testing class B:\n"); 
echo (B::myStaticOverridePropertyTest(). "\n"); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 
echo (" now invoking B::modStaticProperty()  .\n"); 
B::modStaticProperty(); 
echo (B::myStaticValueOverwritePropertyTest(). "\n"); 

echo ("-- now re-testing class A:\n"); 
echo (A::myStaticOverridePropertyTest(). "\n"); 
echo (A::myStaticValueOverwritePropertyTest(). "\n"); 
echo (A::myStaticMethodTest(). "\n"); 

Esta salida voluntad:

- clase de prueba A:
clase A var - override
clase A var2 - valor sobrescribir
valor de la clase A
- clase ahora pruebas B:
clase B var - anula
clase A var2 - sobrescribe valor
ahora invocando B :: modStaticProperty() ...
clase B - valor alterado! - sobrescritura de valor
- ahora volver a probar la clase A:
clase A var - anular
clase B - valor alterado! - Valor sobrescribir
valor de la clase A

Y aquí estamos, se puede ver la diferencia entre las propiedades estáticas anulado y el único valor sobrescrito ... mira la línea de salida he marcado con negrita! Cuando invocamos el modStaticProperty() de la clase B, también cambió el valor de esa variable estática en la clase A. ¡Dado que esa propiedad estática se heredaba y no se anulaba! Piénselo ...

+0

No funcionará si los campos son públicos y cambiados fuera. http://sandbox.onlinephpfunctions.com/code/5d5e947898ea3e4f14e742dd9c9792988fd18dac –

+0

TL; DR: Necesita usar 'static :: $ myStaticProperty' en lugar de usar' self :: $ myStaticProperty';) – T30

Cuestiones relacionadas