2010-02-27 13 views
5

Estoy trabajando en una clase que necesita ser accesible a través de llamadas a funciones estáticas y métodos de objetos. Una cosa que he encontrado es que estoy duplicando la lógica en múltiples funciones.

ejemplo simplificado:

class Configurable{ 

    protected $configurations = array(); 

    protected static $static_configurations = array(); 

    public function configure($name, $value){ 

     // ...lots of validation logic... 

     $this->configurations[$name] = $value; 

     } 

    public static function static_configure($name, $value){ 

     // ...lots of validation logic (repeated)... 

     self::$static_configurations[$name] = $value; 

     } 

    } 

he encontrado una solución a este, pero se siente muy sucio:

class Configurable{ 

    protected $configurations = array(); 

    protected static $static_configurations = array(); 

    public function configure($name, $value){ 

     // ...lots of validation logic... 

     if (isset($this)){ 
      $this->configurations[$name] = $value; 
      } 
     else{ 
      self::$static_configurations[$name] = $value; 
      } 

     } 

    } 

Necesito la función estática, así por lo que puedo ajustar las configuraciones de largo la aplicación. Además, lo bueno de esta técnica es que puedo usar los mismos nombres de método en ambos ámbitos.

¿Hay algún problema con el alcance de prueba de esta manera? Problemas de rendimiento, problemas de compatibilidad con versiones anteriores, etc. Todo funciona para mí en PHP 5.2 y no necesito admitir < 5.

Respuesta

2

El problema con el segundo método es que generará un error cuando se informe un error está configurado en E_STRICT. Por ejemplo:

normas estrictas: método no estático Foo :: bar() no debe ser llamado estáticamente en /home/yacoby/dev/php/test.php en la línea 10

A señalar con PHP6 es que los errores E_STRICT se mueven a E_ALL. En otras palabras, E_ALL cubrirá todos los errores, incluido el no permitirle llamar a métodos no estáticos de forma estática.

Un método alternativo puede ser mover la lógica de validación a una función estática. De esta forma, la función no estática y la función estática pueden llamar a la lógica de validación.

+1

OK, aparte del estricto error, ¿hay algún problema con el segundo método? Probablemente lo cambie en su consejo de todos modos, pero me gustaría entender los problemas reales con el uso de un código como este. ¿Es una característica que probablemente se eliminará de futuras versiones de PHP o siempre podrá llamar a métodos no estáticos de forma estática? – Rowan

+1

Los errores de "E_STRICT" tienden a ser "Esto parece una muy mala idea, pero vamos a dejar que intentes hacerlo de todos modos". No hay garantías de que algo así siempre funcione, pero probablemente se convertirán en 'E_NOTICE' o' E_WARN' antes de ser completamente obsoletos. – MightyE

+0

Gracias por aclarar que @MightyE – Rowan

2

Los métodos estáticos requerirían un número de argumentos diferente al de su homólogo objetivo; el argumento adicional sería un contexto de ejecución. Si no hay contexto de ejecución, entonces solo tiene sentido llamarlo estáticamente.

Mi enfoque preferido, dado que estoy construyendo una biblioteca con múltiples interfaces como esta, es crear una clase estática y una clase dinámica. Tener un proxy las llamadas a la otra. Por ejemplo:

class DynamicClass { 
    protected $foo; 
    protected $bar; 
    public function baz($arg1) { 
     return StaticClass::bar($this->foo, $arg1); 
    } 
    public function zop($arg1, $arg2) { 
     return StaticClass::zop($this->foo, $this->bar, $arg1, $arg2); 
    } 
    // Context-less helper function 
    public function womp($arg1) { 
     return StaticClass::womp($arg1); 
    } 
} 

class StaticClass { 
    public static function baz(&$fooContext, $arg1) { ... } 
    public static function zop(&$fooContext, &$barContext, $arg1, $arg2) { ... } 
    public static function womp($arg1) { ... } 
} 

le toca a usted exactamente cómo se pasa de contexto a la clase estática - que tendrá que hacer lo que tiene sentido para usted. El trabajo realizado en la mayoría de las funciones debería ser bastante menor (si está haciendo mucho, entonces probablemente debería dividir el trabajo en funciones más pequeñas por regla general), por lo que solo debería requerir un puñado de argumentos contextuales. O bien, podría crear una matriz contexto completo y pasar que por todas partes (ya sea poblarlo en DynamicClass justo antes de cada llamada, o bien realizar un seguimiento de todos los DynamicClass propiedades en esa matriz para que pueda rápidamente & pasar fácilmente a su alrededor.


Aunque en realidad parece que podría beneficiarse de un patrón de diseño de Singleton. Por lo que puedo ver, está tratando de crear un Configurable global, y también tiene la opción de crear Configurable s locales individuales. Con el patrón de diseño singleton, crea una versión de acceso global de una clase que puede garantizar que solo tiene una (sin romper los principios de diseño de OOP y tener que depender de $ _GLOBALS, etc.).Por ejemplo:

class DynamicClass { 
    protected $foo; 
    protected $bar; 

    public function baz($arg1) { ... } 
    public function zop($arg1, $arg2) { ... } 

    public static function getSingleton() { 
     static $instance = null; 
     if ($instance === null) $instance = new DynamicClass(); 
     return $instance; 
    } 
} 

No importa en su código usted es, usted puede tener acceso a la misma instancia con DynamicClass::getSingleton(). También tiene la opción de crear versiones únicas no únicas. Básicamente, obtienes lo mejor de ambos mundos y solo tienes que escribir todos tus métodos con acceso dinámico en mente exclusivamente.

2

No me parece tan absurdo permitir llamar a un método en una instancia y estáticamente también. Mi caso:

TestRecord::generateForm(); // Generate an empty form. 

    $test = new TestRecord($primaryKey); 
    [...] 
    $test->generateForm();  // Generate an edit form with actual $test values. 

lado estático de mis clase aborda en blanco/nuevas lógicas, mientras que el lado instancia significa se utilizan datos en tiempo real.

PHP 5.3 permite lograr esto usando __call, __callStatic y static:::

public function __call($name, $args) 
{ 
    if ($name == 'generateForm') { 
    $this->fields = static::createFields(); // Action 1 : static. 
    $this->fillFields();      // Action 2 : instance. 
    static::renderForm($this->fields);  // Action 3 : static. 
    } 
} 

public static function __callStatic($name, $args) 
{ 
    if ($name == 'generateForm') { 
    $fields = static::createFields();  // Action 1 : static. 
              // Action 2 : none. 
    static::renderForm($fields);   // Action 3 : static. 
    } 
} 

Nota: El calificador el enlace static:: se usa porque se implementan mis 3 métodos de acción (createFields, fillFields y rendreForm) como protected en las subclases de este, que es abstract. Esto es posible porque PHP permite acceder a los miembros protegidos en ambas direcciones: de la base a la subclase, pero también de la subclase a la superclase. Que yo sepa, es diferente de otros lenguajes OO.

-1

como en php núcleo utilizamos index.php?var=, por lo que hacer lo mismo en php oop lo que debemos utilizar.

Cuestiones relacionadas