PHP get_称为_class()可选
我有一个抽象的PHP超类,其中包含需要知道它在哪个子类下运行的代码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
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
”。这与我的想法不完全一样,但这可能有效。