Estendendo classs estáticas em PHP – Evitando as variables ​​de compartilhamento para várias classs na class estendida

Parece ter problemas para estender as aulas estáticas em PHP.

Código PHP:

<?php class InstanceModule { public static $className = 'None'; public static function PrintClassName() { echo self::$className . ' (' . __CLASS__ . ')
'; } } class A extends InstanceModule { public static function Construct() { self::$className = "A"; } } class B extends InstanceModule { public static function Construct() { self::$className = "B"; } } ?>

Meu código de chamada e o que eu esperaria:

  

Saída completa real:

 None (InstanceModule) None (InstanceModule) A (InstanceModule) A (InstanceModule) B (InstanceModule) B (InstanceModule) A (InstanceModule) A (InstanceModule) 

Então, o que está acontecendo aqui (do que parece) é que, assim que eu definir self::$className em qualquer uma das classs que se estendem, ela substitui a variável da outra class. Eu suponho que isso é porque eu uso classs estáticas, e só pode haver uma class InstanceModule vez de simplesmente copiá-la para A e B , assim como minha compreensão anterior extends . Eu tentei usar a palavra-chave static::$className vez disso, mas parece não fazer diferença.

Seria adorável se alguém pudesse me guiar na direção certa do que eu estou fazendo errado aqui e o que fazer para resolver esse problema.

Editar : para esclarecer, este código faz o que eu quero, mas é obviamente uma solução horrível, pois isso arruinaria toda a idéia de ampliar e reutilizar funções:

 <?php class A { public static $className = 'None'; public static function PrintClassName() { echo self::$className . ' (' . __CLASS__ . ')
'; } public static function Construct() { self::$className = "A"; } } class B { public static $className = 'None'; public static function PrintClassName() { echo self::$className . ' (' . __CLASS__ . ')
'; } public static function Construct() { self::$className = "B"; } } ?>

Uma vez que $ className é estático e dentro da class pai, quando você define className dentro de A ou B, ele muda a variável dentro do pai, e o mesmo é feito quando a variável é lida. A menos que você substitua className em suas classs estendidas, você estará armazenando e recuperando informações do mesmo local de memory, originalmente definido em InstanceModule.

Se você redefinir className em A / B, você pode acessar className usando parent :: ou self :: from InstanceModule ou A / B, respectivamente. Dependendo do que você está tentando fazer, as aulas abstratas também podem desempenhar um papel significativo.

Veja Palavra – chave estática ou Abstração de classs no Manual do PHP5.

Eu acho que a melhor resposta para sua situação é usar a function get_called_class() vez da sua variável $className atual, que retornará o nome da class de binding estática tardia em vez de __CLASS__ ou get_class() que só retornará o nome da class atual.

Se você alterou sua function PrintClassName() para apenas exibir o que get_called_class() retornou, sua saída seria a seguinte. Agora, você precisaria incorporar um valor padrão, que, claro, será compartilhado entre as classs, então você teria que ter essa bandeira em ambas as classs se você continuar usando methods estáticos.

 A B A B A B A B 

Eu teria a class base manter um repository de instâncias de subclass, de modo que você possa separar separadamente dados que pertençam a cada class em vez de retirar esses dados de uma variável de class base estática.

Você pode usar o método mágico __callStatic() na class base para realizar methods de chamada em sub-classs inexistentes, conforme demonstrado abaixo. Infelizmente, a variável do repository estático deve ser declarada pública devido à visibilidade desse método mágico.

 abstract class Base { public static $repo = array(); public static function __callStatic($name, $args) { $class = get_called_class(); if (!isset(self::$repo[$class])) { echo "Creating instance of $class\n"; self::$repo[$class] = new $class(); } return call_user_func_array(array(self::$repo[$class], $name), $args); } protected function PrintClassName() { echo __CLASS__, " (", get_called_class(), ")\n"; } protected abstract function Construct($a); } class A extends Base { protected function Construct($a) { echo __CLASS__, ": setting x := $a\n"; } } class B extends Base { protected function Construct($a) { echo __CLASS__, ": setting y := $a\n"; } } A::PrintClassName(); B::PrintClassName(); A::Construct('X'); B::Construct('Y'); 

Saída:

 Creating instance of A Base (A) Creating instance of B Base (B) A: setting x := X B: setting y := Y