如何从扩展 PHP 类中的静态调用获得类名?

我有两个类: ActionMyAction。后者被声明为:

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

我所需要的只是 Action类中的方法(只在它中使用,因为将有很多继承的类,我不想在所有类中都实现这个方法) ,它将从静态调用返回 classname。这就是我要说的:

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

当我说:

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

但是父类中的每个声明只能访问父类 __CLASS__变量,该变量的值为“ Action”。

有什么可行的办法吗?

70358 次浏览

__CLASS__ always returns the name of the class in which it was used, so it's not much help with a static method. If the method wasn't static you could simply use get_class($this). e.g.

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


}


class MyAction extends Action {


}


$foo=new MyAction;


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

Late static bindings, available in PHP 5.3+

Now that PHP 5.3 is released, you can use late static bindings, which let you resolve the target class for a static method call at runtime rather than when it is defined.

While the feature does not introduce a new magic constant to tell you the classname you were called through, it does provide a new function, get_called_class() which can tell you the name of the class a static method was called in. Here's an example:

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




class MyAction extends Action {


}




echo MyAction::n(); //displays MyAction

There is no way, in the available PHP versions, to do what you want. Paul Dixon's solution is the only one. I mean, the code example, as the late static bindings feature he's talking about is available as of PHP 5.3, which is in beta.

Now (when 5.3 has arrived) it's pretty simple:

http://php.net/manual/en/function.get-called-class.php

It's not the ideal solution, but it works on PHP < 5.3.0.

The code was copied from 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();
}
}
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();

Since 5.5 you can use class keyword for the class name resolution, which would be a lot faster than making function calls. Also works with 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

(PHP 5 >= 5.3.0, PHP 7)
get_called_class — The "Late Static Binding" class name

<?php


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


class User extends Model
{
}




echo User::find();

this link might be helpfull