¿Cómo puedo obtener el nombre de la clase de una llamada estática en una clase PHP extendida?

93

Tengo dos clases: Actiony MyAction. Este último se declara como:

class MyAction extends Action {/* some methods here */}

Todo lo que necesito es un método en la Actionclase (solo en él, porque habrá muchas clases heredadas y no quiero implementar este método en todas), que devolverá el nombre de clase de una llamada estática. Esto es de lo que estoy hablando:

Class Action {
 function n(){/* something */}
}

Y cuando lo llamo:

MyAction::n(); // it should return "MyAction"

Pero cada declaración en la clase principal tiene acceso solo a la __CLASS__variable de la clase principal , que tiene el valor "Acción".

¿Hay alguna forma posible de hacer esto?

Anton
fuente

Respuestas:

176

__CLASS__siempre devuelve el nombre de la clase en la que se usó, por lo que no es de mucha ayuda con un método estático. Si el método no fuera estático, simplemente podría usar get_class ($ this). p.ej

class Action {
    public function n(){
        echo get_class($this);
    }

}

class MyAction extends Action {

}

$foo=new MyAction;

$foo->n(); //displays 'MyAction'

Enlaces estáticos tardíos, disponibles en PHP 5.3+

Ahora que se lanzó PHP 5.3, puede usar enlaces estáticos tardíos , que le permiten resolver la clase de destino para una llamada de método estático en tiempo de ejecución en lugar de cuando está definida.

Si bien la función no introduce una nueva constante mágica para decirle el nombre de clase a través del cual fue llamado, sí proporciona una nueva función, get_called_class () que puede indicarle el nombre de la clase en la que se llamó a un método estático. Aquí hay un ejemplo:

Class Action {
    public static function n() {
        return get_called_class();
    }
}


class MyAction extends Action {

}


echo MyAction::n(); //displays MyAction
Paul Dixon
fuente
El único problema para el OP es que la función aún no está disponible. PHP 5.3 aún está en fase beta.
Ionuț G. Stan
3
@Paul, ¡gracias! Acabas de get_called_class()
salvarme el
1
Ojalá alguien pudiera ayudarme con un problema similar . El script PHP muere silenciosamente al ejecutarse new static();desde dentro de un método estático privado (usando xampp en Windows y php> 5.5). :s
Stphane
$ foo = new MyAction; echo get_class ($ foo); Esto también imprime MyAction.
sammry
41

Desde 5.5, puede usar classpalabras clave para la resolución del nombre de la clase , lo que sería mucho más rápido que hacer llamadas a funciones. También funciona con interfaces.

// C extends B extends A

static::class  // MyNamespace\ClassC when run in A
self::class    // MyNamespace\ClassA when run in A
parent::class  // MyNamespace\ClassB when run in C
MyClass::class // MyNamespace\MyClass
Ian Bytchek
fuente
16

No es la solución ideal, pero funciona en PHP <5.3.0.

El código fue copiado de septuro.com

if(!function_exists('get_called_class')) {
    class class_tools {
        static $i = 0;
        static $fl = null;

        static function get_called_class() {
            $bt = debug_backtrace();

            if (self::$fl == $bt[2]['file'].$bt[2]['line']) {
                self::$i++;
            } else {
                self::$i = 0;
                self::$fl = $bt[2]['file'].$bt[2]['line'];
            }

            $lines = file($bt[2]['file']);

            preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/',
                $lines[$bt[2]['line']-1],
                $matches);

            return $matches[1][self::$i];
        }
    }

    function get_called_class() {
        return class_tools::get_called_class();
    }
}
Jrgns
fuente
2
class MainSingleton { 
  private static $instances = array(); 
  private static function get_called_class() {
    $t = debug_backtrace();
    return $t[count($t)-1]["class"];
  }  

  public static function getInstance() { 
    $class = self::get_called_class();
    if(!isset(self::$instances[$class]) ) { 
      self::$instances[$class] = new $class; 
    } 
    return self::$instances[$class]; 
  } 

}

class Singleton extends MainSingleton { 
  public static function getInstance()
  {
    return parent::getInstance();
  }     
  protected function __construct() { 
    echo "A". PHP_EOL; 
  } 

  protected function __clone() {} 

  public function test() { 
    echo " * test called * "; 
  } 
} 

Singleton::getInstance()->test(); 
Singleton::getInstance()->test();
Lulú
fuente
0

No hay forma, en las versiones PHP disponibles, de hacer lo que quiera. La solución de Paul Dixon es la única. Quiero decir, el ejemplo de código, ya que la última función de enlaces estáticos de la que habla está disponible a partir de PHP 5.3, que está en versión beta.

Ionuț G. Stan
fuente
0

(PHP 5> = 5.3.0, PHP 7)
get_called_class - El nombre de la clase "Enlace estático tardío"

<?php

class Model
{
  public static function find()
  {
    return get_called_class();
  }
}

class User extends Model
{
}


echo User::find();

este enlace puede ser útil

Biswajit Biswas
fuente