metodo - Falsificación de unión estática tardía antes de php 5.3
public static php (6)
A menudo, el enlace estático tardío es necesario cuando un niño llama a un método del padre que, a su vez, llama a un método estático abstracto del niño. Estaba en esa posición y no podía usar static :: ya que mi PHP no era la versión 5.3 (o posterior). La siguiente unión estática tardía realizada mediante debug_backtrace ().
abstract class ParentClass
{
static function parent_method()
{
$child_class_str = self::get_child_class();
eval("/$r = ".$child_class_str."::abstract_static();");
return $r;
}// CHILD MUST OVERRIDE TO PUT ITSELF INTO TRACE
protected abstract static function abstract_static(); // THIS NEEDS LATE STATIC BINDING
private static function get_child_class()
{
$backtrace = debug_backtrace();
$num = count($backtrace);
for($i = 0; $i < $num; $i++)
{
if($backtrace[$i]["class"] !== __CLASS__)
return $backtrace[$i]["class"];
}
return null;
}
}
class ChildClass extends ParentClass
{
static function parent_method(){ return parent::parent_method(); }
protected static function abstract_static()
{
return __METHOD__."()";
}// From ParentClass
}
print "The call was: ". ChildClass::parent_method();
Necesito una función estática "llamada" heredada para llamar a otra función estática "interna" que ha sido anulada. Podría hacer esto con enlace estático tardío, pero mi servidor aún no tiene php5.3, así que tengo que solucionarlo.
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
Me gustaría que la salida sea:
Clase A = Clase A
Clase B = Clase B
Pero lo que es:
Clase A = Clase A
Clase B = Clase A
Mi intuición me dice que debería poder escribir algo en call () para detectar a qué objeto se hizo referencia cuando, así, se llamó a "call ()". Entonces en lugar de self :: inner () sería algo parecido a calledclass :: inner (). Detectando la versión correcta de inner () para llamar desde la llamada al método original.
Aquí hay un ejemplo rápido.
<?php
class ClassA{
public function call(){
return $this->inner();
}
static function inner(){
return "Class A";
}
static function init($class){
return new $class();
}
}
class ClassB extends ClassA{
static function inner(){
return "Class B";
}
}
echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();
?>
Si no le gusta pasar el nombre de la clase, puede agregar una función de inicio estático a la clase secundaria y explícitamente pasarla allí también. Esto le permitiría hacer algo como: ClassA :: init () -> call () y ClassB :: init () -> call () pero tendría alguna duplicación de código menor.
Como no puede usar static ::, o get_called_class (), o __callStatic, tendrá que llamar a la función inner () con alguna indicación con la clase llamada (como se menciona en las otras respuestas). Una instancia de la clase llamada estaría bien. Puede agregar métodos "Pseudo Static" para imitar todos los métodos estáticos que necesita sobreescribir. Esto dobla su código, pero al hacer esto como a continuación, espero que el código sea más fácil de actualizar una vez que php5.3 aparece: simplemente elimine todos los métodos ps y todas las funciones que los referencian (y cambie "self" a "static" donde necesario ..)
class ClassA{
static function call()
{
return self::inner();
}
static function inner(){
return "Class A";
}
public function _ps_call()
{
return $this->_ps_inner();
}
}
class ClassB extends ClassA{
public static function getInstance()
{
return new self();
}
public static function call()
{
return self::getInstance()->_ps_call();
}
static function inner()
{
return "Class B";
}
public function _ps_inner()
{
return self::inner();
}
}
echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();
Lamentablemente, no hay una buena manera de hacerlo (de lo contrario, los PHPers no animarían tanto por esa característica).
Tienes que pasar el nombre de la clase. PHP <5.3 tampoco tiene buena sintaxis para llamadas estáticas con nombre de clase dinámico que hace que todo sea aún más feo:
static function call($class)
{
return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");
Si puede cambiar el código (y no usar static
), entonces los singleton lo hacen más soportable. Puede hacer que la función auxiliar mejore la sintaxis:
X("ClassA")->call();
X("ClassB")->call();
La función X debe buscar, crear y devolver instancia de una clase.
Puede usar instancias de objetos en lugar de clases. Si quieres un símbolo global, puedes usar una variable global. Dado que son bastante difíciles de manejar en PHP, un truco es envolverlo en una función. P.ej.:
class ClassA {
function call() {
return $this->inner();
}
function inner() {
return "Class A";
}
}
function ClassA() {
static $instance;
return $instance ? $instance : new ClassA();
}
class ClassB extends ClassA {
function inner() {
return "Class B";
}
}
function ClassB() {
static $instance;
return $instance ? $instance : new ClassB();
}
echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();
Pero una mejor idea podría ser evitar los símbolos globales por completo; La razón por la que funciona bien en Ruby / Rails es que Ruby no tiene estado estático de la misma manera que PHP. Una clase puede recuperarse y agregarse en tiempo de ejecución, lo que permite una fácil extensión del marco. En PHP, las clases son siempre finales, por lo que referirse a ellas en el código de la aplicación es un grado muy fuerte de acoplamiento.
Si el rendimiento no es un problema, puede usar debug_backtrace () para encontrar la clase llamada:
$bt = debug_backtrace();
return get_class($bt[1][''object'']);