PHP get_称为_class()可选

PHP get_称为_class()可选,php,oop,inheritance,php-5.2,Php,Oop,Inheritance,Php 5.2,我有一个抽象的PHP超类,其中包含需要知道它在哪个子类下运行的代码 class Foo { static function _get_class_name() { return get_called_class(); //works in PHP 5.3.*, but not in PHP 5.2.* } static function other_code() { //needs to know echo

我有一个抽象的PHP超类,其中包含需要知道它在哪个子类下运行的代码

class Foo {
    static function _get_class_name() {
        return get_called_class();
        //works in PHP 5.3.*, but not in PHP 5.2.*
    }

    static function other_code() {
        //needs to know
        echo self::_get_class_name();
    }
}

class Bar extends Foo {
}

class FooBar extends Foo {
}

Bar::other_code(); // i need 'Bar'
FooBar::other_code(); // i need 'FooBar'
如果我调用函数
get_called_class()
,这将起作用——但是,这段代码将在PHP版本5.2.*中运行,因此该函数不可用

有一些自定义的PHP实现
get_called_class()
,但是它们都依赖于通过
debug_backtrack()
,解析文件名和行号,并运行正则表达式(因为编码者不知道PHP5.2有反射)来查找类名。此代码需要能够与php一起运行,即不仅仅从.php文件运行。(它需要从
php-a
shell或
eval()
语句中工作。)

理想情况下,解决方案可以在不需要向子类添加任何代码的情况下工作……但我能看到的唯一可能的解决方案是向每个子类添加以下代码,这显然是一个令人厌恶的黑客行为:

class FooBar extends Foo {
    static function _get_class_name() {
        return 'FooBar';
    }
}
编辑:等等,这似乎根本不起作用。这将是我最后的选择。有人能想出类似的解决方案,让我获得所需的功能吗。也就是说,我愿意接受一种解决方案,要求我向每个子类添加一个函数或变量,告诉它它的类名是什么。不幸的是,从超类调用self::_get_class_name()似乎会调用父类的实现,即使子类已经覆盖了它。

这是不可能的

PHP5.3中引入了“调用类”的概念。在以前的版本中未跟踪此信息


作为一种难看的解决方法,您可能会使用
debug\u backtrace
查看调用堆栈,但它不是等效的。例如,在PHP5.3中,使用
ClassName::method()
不会转发静态调用;使用
debug\u backtrace
无法判断这一点。另外,
debug\u backtrace
相对较慢。

我以前问过这样一个问题,因为我希望父级有一个类似这样的工厂方法

public static function factory() {
    return new __CLASS__;
}
但是它总是返回父类,而不是继承的类

有人告诉我,没有后期静态绑定是不可能的。它是在PHP5.3中引入的。您可以阅读。

解决方案是:

get_class($this);
然而,我不知道这个句子在静态函数中是否有效。请尝试一下并告诉我您的反馈。

实际上,在执行超类方法时,了解实际调用的(子)类通常很有帮助,我不认为想要解决这个问题有什么不对

例如,我的对象需要知道类名,但它们对这些信息所做的操作总是相同的,如果我能够获得被调用的类名,它们可以被提取到超类方法中。甚至PHP团队也认为这足够有用,可以包含在PHP5.3中


据我所知,正确且不具说教性的答案是,在5.3之前,您必须做一些令人发指的事情(例如,回溯),或者只是在每个子类中包含重复的代码。

这种黑客行为包括了对debug\u回溯的令人发指的使用。。。不漂亮,但它确实起到了作用:

<?php 
function callerName($functionName=null)
{
    $btArray = debug_backtrace();
    $btIndex = count($btArray) - 1;
    while($btIndex > -1)
    {
        if(!isset($btArray[$btIndex]['file']))
        {
            $btIndex--;
            if(isset($matches[1]))
            {
                if(class_exists($matches[1]))
                {
                    return $matches[1];
                }
                else
                {
                    continue;
                }
            }
            else
            {
                continue;
            }
        }
        else
        {
            $lines = file($btArray[$btIndex]['file']);
            $callerLine = $lines[$btArray[$btIndex]['line']-1];
            if(!isset($functionName))
            {
                preg_match('/([a-zA-Z\_]+)::/',
                $callerLine,
                $matches);
            }
            else
            {
                preg_match('/([a-zA-Z\_]+)::'.$functionName.'/',
                    $callerLine,
                    $matches);
            }
            $btIndex--;
            if(isset($matches[1]))
            {
                if(class_exists($matches[1]))
                {
                    return $matches[1];
                }
                else
                {
                    continue;
                }
            }
            else
            {
                continue;
            }
        }
    }
    return $matches[1];
}
工作解决方案:

function getCalledClass(){
    $arr = array(); 
    $arrTraces = debug_backtrace();
    foreach ($arrTraces as $arrTrace){
       if(!array_key_exists("class", $arrTrace)) continue;
       if(count($arr)==0) $arr[] = $arrTrace['class'];
       else if(get_parent_class($arrTrace['class'])==end($arr)) $arr[] = $arrTrace['class'];
    }
    return end($arr);
}

此函数执行相同的任务,但也适用于实例:

if (!function_exists('get_called_class')) {

    function get_called_class() {

        $bt = debug_backtrace();

        /*
            echo '<br><br>';
            echo '<pre>';
            print_r($bt);
            echo '</pre>';
        */

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

        if ($bt[1]['type'] == '::') {

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

        } else if ($bt[1]['type'] == '->') {

            $result = get_class($bt[1]['object']);
        }

        return $result;
    }
}
如果(!function_存在('get_调用_class')){
函数get_称为_类(){
$bt=debug_backtrace();
/*
回音“

”;
abstract class Transaction{
    public $id;

    public function __construct($id){
        $this->id = $id;
    }

    protected static function getInstanceHelper($class_name, $id){
        return new $class_name($id);
    }
}

class Payment extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

class Refund extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

var_dump( Payment::getInstance(1), Refund::getInstance(2) );
回声';
abstract class Transaction{
    public $id;

    public function __construct($id){
        $this->id = $id;
    }

    protected static function getInstanceHelper($class_name, $id){
        return new $class_name($id);
    }
}

class Payment extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

class Refund extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

var_dump( Payment::getInstance(1), Refund::getInstance(2) );
印刷费($bt); 回声';
abstract class Transaction{
    public $id;

    public function __construct($id){
        $this->id = $id;
    }

    protected static function getInstanceHelper($class_name, $id){
        return new $class_name($id);
    }
}

class Payment extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

class Refund extends Transaction{
    public static function getInstance($id){
        return parent::getInstanceHelper(__CLASS__, $id);
    }
}

var_dump( Payment::getInstance(1), Refund::getInstance(2) );
*/ 如果(self::$fl==$bt[1]['file'].$bt[1]['line'])){ self::$i++; }否则{ self::$i=0; self::$fl=$bt[1]['file'].$bt[1]['line']; } 如果($bt[1]['type']==':'){ $lines=file($bt[1]['file']); preg_match_all('/([a-zA-Z0-9\\\\\\\\\\\]+):'.$bt[1]['function'].'/',$lines[$bt[1]['line']-1],$matches); $result=$matches[1][self::$i]; }else if($bt[1]['type']=='->')){ $result=get_类($bt[1]['object']); } 返回$result; } }
对于后期静态绑定,PHP/5.2的替代方案是在将类名作为参数传递的子类上创建一行程序,以将重复代码保持在最低限度,同时避免奇怪的攻击:

<?php

class Foo {

    private static $instance;

    static function _get_class_name() {
        return self::myNameIs();
    }

    static function other_code() {
        //needs to know
        echo self::_get_class_name();
    }

}

class Bar extends Foo {

    public static function myNameIs() {
        self::$instance = new Bar();
        return get_class(self::$instance);
    }

}

class FooBar extends Foo {

    public static function myNameIs() {
        self::$instance = new FooBar();
        return get_class(self::$instance);
    }

}

Bar::other_code(); // i need 'Bar'
FooBar::other_code(); // i need 'FooBar'
对象(付款)#1(1){
[“id”]=>
int(1)
}
反对(退款)#2(1){
[“id”]=>
int(2)
}

老实说,您最好的解决方案是升级到5.3。我知道,但不幸的是,这不是一个选项。我们在java中如何做到这一点?debug_backtrace将类列为超类而不是子类。它列出了调用它的文件和行号,因此理论上我可以在其中对行进行正则化以查找被调用的类,假设它是用Bar::format调用的,但这不是真正的解决方案。在shell的上下文中,如果文件名被愚蠢地列为“php shell代码”@Ken Yes,
debug\u backtrace
糟糕透顶,那么它就不起作用了。不幸的是,您唯一剩下的选项是1)升级,2)替换每个子类中的静态方法
other\u code
\u get\u class\u name
),因为从超类中的
other\u code
实现调用它将导致始终调用超类的版本。这是可能的。试试eval;)虽然绝对可怕,但为提供运行时解决方案而付出的努力+1。我想,如果有人需要拼命支持php,那么很不幸,您的实现并不能正常工作。考虑下面的例子:<代码>类A{public static函数FoE(){RealGeCaldiLeClass();}类B扩展了{}回声B::FoW();<代码>。预期的结果是“B”(这是使用
get\u called\u class()
)时得到的结果),但这里我们得到的是“A”。这基本上是静态方法的定义:“no
$this
”。这与我的想法不完全一样,但这可能有效。