Como posso obter o nome da classe de uma chamada estática em uma classe PHP estendida?

91

Tenho duas classes: Actione MyAction. Este último é declarado como:

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

Tudo que preciso é um método na Actionclasse (apenas nele, porque haverá muitas classes herdadas e não quero implementar esse método em todas elas), que retornará classname de uma chamada estática. Aqui está o que estou falando:

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

E quando eu chamo:

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

Mas cada declaração na classe pai tem acesso apenas à __CLASS__variável da classe pai , que tem o valor “Ação”.

Existe alguma maneira possível de fazer isso?

Anton
fonte

Respostas:

176

__CLASS__sempre retorna o nome da classe na qual foi usado, portanto, não ajuda muito com um método estático. Se o método não fosse estático, você poderia simplesmente usar get_class ($ this). por exemplo

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

}

class MyAction extends Action {

}

$foo=new MyAction;

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

Vinculações estáticas tardias, disponíveis em PHP 5.3+

Agora que o PHP 5.3 foi lançado, você pode usar vinculações estáticas tardias , que permitem resolver a classe de destino para uma chamada de método estático em tempo de execução, em vez de quando ela é definida.

Embora o recurso não introduza uma nova constante mágica para informar o nome da classe através do qual você foi chamado, ele fornece uma nova função, get_called_class (), que pode informar o nome da classe em que um método estático foi chamado. Aqui está um exemplo:

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


class MyAction extends Action {

}


echo MyAction::n(); //displays MyAction
Paul Dixon
fonte
O único problema do OP é que o recurso ainda não está disponível. PHP 5.3 ainda está em beta.
Ionuț G. Stan
3
@Paul, obrigado! Você acabou de salvar meu dia ... ou noite com get_called_class():)
Marecky
1
Eu gostaria que alguém pudesse me ajudar com um problema semelhante . O script PHP morre silenciosamente ao ser executado new static();de dentro de um método estático privado (usando xampp no ​​Windows e php> 5.5). :s
Stphane
$ foo = new MyAction; echo get_class ($ foo); Isso também imprime MyAction.
sammry
40

Desde o 5.5 você pode usar classpalavras-chave para a resolução do nome da classe , o que seria muito mais rápido do que fazer chamadas de função. Também funciona com 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
fonte
16

Não é a solução ideal, mas funciona em PHP <5.3.0.

O código foi 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
fonte
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();
Lulu
fonte
0

Não há como, nas versões PHP disponíveis, fazer o que você quer. A solução de Paul Dixon é a única. Quero dizer, o exemplo de código, como o recurso de vinculação estática tardia de que ele está falando, está disponível a partir do PHP 5.3, que está em beta.

Ionuț G. Stan
fonte
0

(PHP 5> = 5.3.0, PHP 7)
get_called_class - O nome da classe "Late Static Binding"

<?php

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

class User extends Model
{
}


echo User::find();

este link pode ser útil

Biswajit Biswas
fonte