PHP isset ($ this) e usando o mesmo método de object em um contexto estático e de object

Estou trabalhando em uma class que precisa ser acessível através de chamadas de function estática, bem como methods de object. Uma coisa que encontrei é que estou duplicando a lógica em várias funções.

Exemplo 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; } } 

Encontrei uma solução para isso, mas parece muito sujo:

 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; } } } 

Eu também preciso da function estática para que eu possa definir configurações ao longo da aplicação. Além disso, a coisa boa com esta técnica é que eu posso usar os mesmos nomes de methods em ambos os escopos.

Existem problemas com o escopo de teste como este? Problemas de desempenho, problemas de compatibilidade de frente, etc. Tudo funciona para mim no PHP 5.2 e não preciso suportar <5.

O problema com o segundo método é que isso resultará em um erro quando o relatório de erro for definido como E_STRICT . Por exemplo:

Normas estritas: método não-estático Foo :: bar () não deve ser chamado de forma estática em /home/yacoby/dev/php/test.php na linha 10

Um ponto com PHP6 é que os erros E_STRICT são movidos para E_ALL. Em outras palavras, o E_ALL irá cobrir todos os erros, incluindo não permitir que você lembre methods estáticos não estáticos.

Um método alternativo pode ser mover a lógica de validação para uma function estática. Dessa forma, a function não estática e a function estática podem chamar a lógica de validação.

Os methods estáticos exigiriam um número diferente de argumentos do que a contrapartida objetiva – o argumento adicional seria um contexto de execução. Se não houver um contexto de execução, faz sentido chamá-lo de forma estática.

Minha abordagem preferida, dado que estou construindo uma biblioteca com múltiplas interfaces como essa, é criar uma class estática e uma class dinâmica. Ter um proxy para as chamadas para outro. Por exemplo:

 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) { ... } } 

Depende de você exatamente como você passa o contexto para a class estática – você terá que fazer o que faz sentido para você. O trabalho realizado na maioria das funções deve ser bastante menor (se você estiver fazendo muito, então você provavelmente deve estar dividindo o trabalho em funções menores como uma regra) e, portanto, só deve exigir um punhado de argumentos de contexto. Ou você poderia criar uma matriz de contexto completo e passar por todos os lugares (preenchendo-o em DynamicClass imediatamente antes de cada chamada, ou então rastreie todas as propriedades do DynamicClass dessa matriz para que você possa passá-lo rapidamente e facilmente.


No entanto, parece que você pode se beneficiar de um padrão de design Singleton. Pelo que posso ver, você está tentando criar um Configurable global, e também tem a opção de criar Configurable locais individuais Configurable . Com o padrão de design singleton, você cria uma versão globalmente acessível de uma class que você pode garantir que você tenha apenas um (sem quebrar os princípios de design OOP e ter que depender de $ _GLOBALS, etc.). Por exemplo:

 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; } } 

Não importa onde no seu código você esteja, você pode acessar a mesma instância com DynamicClass::getSingleton() . Você também tem a opção de criar versões one-off non-singleton. Você obtém essencialmente o melhor dos dois mundos, enquanto só tem que escrever todos os seus methods com access dynamic em mente exclusivamente.

Eu não acho tão absurdo permitir a chamada de um método em uma instância e estaticamente também. O meu caso:

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

O lado estático da minha class lida com lógicas em branco / novas, enquanto o lado da instância significa que os dados ao vivo são usados.

O PHP 5.3 permite alcançar isso usando __call , __callStatic e static:: __callStatic

 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 : O qualificador de binding static:: late é usado porque os meus 3 methods de ação ( createFields , fillFields e rendreForm ) são implementados como protected nas subclasss deste, que é abstract . Isso é possível porque o PHP permite que os membros protegidos sejam acessados ​​em ambas as direções: da base para a subclass, mas da subclass para a superclass também. O que é diferente de outras linguagens OO, tanto quanto eu sei.

Como no core php, usamos index.php?var= , para fazer o mesmo no oop php, o que devemos usar.