从$ _SERVER ['SCRIPT_FILENAME']中识别类名

时间:2011-04-20 07:29:29

标签: php regex

如果我的未知类遵循以下模式,获取所请求的PHP文件的类名的最佳方法是什么?

的index.php

<?php
    require_once("startup.php");

    class NotIndex extends View
    {
        public function getView()
        {
            echo "<pre>View Data</pre>";
        }
    }
?>

为了进行测试,我想在NotIndex脚本中创建startup.php类的实例。

startup.php

<?php
    require_once("view.php");

    //Include the script again to bring in the class definition
    include($_SERVER['SCRIPT_FILENAME']);

    //Make sure I'm seeing any errors
    error_reporting(E_ALL);
    ini_set('display_errors','On');

    //If I knew the class I could just do this
    $Page = new NotIndex();
    $Page->getView();

    //Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
    //Todo: Once we find the class create an instance and call getView()

    exit;
?>

view.php

<?php
    abstract class View
    {
        abstract function getView();
    }
?>

我认为正则表达式解决方案可能很简单,因为所需的数据将始终位于“class”和“extends”之间。我没有太多经验来制定所需的表达方式,并且会欣赏一些见解。

以下解决方案可能是也可能不是这样做的好方法,但它确实引导我使用非正则表达式解决方案,这始终是一个优势。如果有人可以改进这一点,那么我很乐意为他们的上述问题给予他们信任。实际上,积分是@Nik回答Stack Overflow问题 Extracting function names from a file (with or without regular expressions) 。如果我在启动脚本中执行此操作,那么我可能会指望未知类是数组中的最后一个。但是,我计划将其集成到我的框架中,并希望有一个更完整的解决方案。

由于班级名称未知,您可能会问我们如何确定?好吧,抽象类View就在数组中未知类之前。任何解决方案肯定都要检查这个。因此,如果不保证最后一个类是所需的类,我可能需要在数组中向后遍历,直到我识别出抽象的View类,并且数组中的前一个值将是未知的子类。

startup.php

<?php
    require_once("view.php");

    //Include the script again to bring in the class definition
    include($_SERVER['SCRIPT_FILENAME']);

    //Make sure I'm seeing any errors
    error_reporting(E_ALL);
    ini_set('display_errors','On');

    //If I knew the class I could just do this
    $Page = new NotIndex();
    $Page->getView();

    //Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
    //Todo: Once we find the class create an instance and call getView()
    $Classes = get_declared_classes();
    $ViewObject = array_pop($Classes);

    $NewPage = new $ViewObject();
    $NewPage->getView();

    exit;
?>
  

查看数据

请扩展有关此用法的任何意见。

所以这个解决方案只有在我通过View再次包含未知子类脚本之前立即包含我的抽象include($_SERVER['SCRIPT_FILENAME']);类时才有效。因此,这意味着get_declared_classes()函数按照定义或包含的顺序添加类。这可能是个问题。

<?php
    require_once("view.php");

    //Include the script again to bring in the class definition
    include($_SERVER['SCRIPT_FILENAME']);
    include("killsolution.php");

    //Make sure I'm seeing any errors
    error_reporting(E_ALL);
    ini_set('display_errors','On');

    //If I knew the class I could just do this
    $Page = new NotIndex();
    $Page->getView();

    //Todo: Find the class from $_SERVER['SCRIPT_FILENAME']
    //Todo: Once we find the class create an instance and call getView()
    $Classes = get_declared_classes();
    $ViewObject = array_pop($Classes);

    $NewPage = new $ViewObject();
    $NewPage->getView();

    exit;
?>
  

致命错误:调用未定义的方法   killsolution :: getView()


(此问题是另一个打开的Stack Overflow问题的一个子集, What are some PHP object-oriented framework initialization techniques?

2 个答案:

答案 0 :(得分:1)

使用__autoload()

如果必须继续沿此路径继续,则可以使用PHPs Tokenizer从文件路径获取类名。正则表达式并不能解决这个问题。

我的一位朋友写了Überloader(PHP5的蛮力自动加载器。),它在索引类文件时使用了这种技术。来自它的_check_file() method将是您特别感兴趣的。

使用Überloader本身甚至可以解决您的问题。它维护一个类名称及其相关文件路径的缓存,因此它比在每个页面加载时使用Tokenizer更快。 Überloader专为未计划或考虑其类命名约定或文件结构的遗留项目而设计。

答案 1 :(得分:0)

以下解决方案允许您迭代在运行时定义的类,在我的情况下,搜索用户定义的View子类。 get_declared_classes()函数将按照包含它们的顺序返回系统和用户定义的类。在包含所请求的脚本类之前,我的系统包含120多个系统类。出于这个原因,我在返回的数组中向后迭代。

<强> startup.php     

//Include the script again to bring in the class definition
include($_SERVER['SCRIPT_FILENAME']);

//Make sure I'm seeing any errors for testing
ini_set('display_errors','On');

//Don't assume we will find a subclass of View
$RequestClass = false;

//Iterate over declared classes starting from the last defined class
for($i = count($classes = get_declared_classes()) - 1; $i >= 0; $i--)
{
    //Test if unknown class is a subclass of abstract View
    if(get_parent_class($classes[$i]) == 'View')
    {
        //Store the name of the subclass of View
        $RequestClass = $classes[$i];

        //We found our unknown View
        break;
    }
}

if($RequestClass)
{
    //We can now instantiate the class or do something useful
    $Page = new $RequestClass();
    $Page->getView();
}

exit;

根据您调用get_declared_classes()函数的时间,数组可能会更改。我知道我的未知类将始终是View的子类,因此无论后来定义了多少类,我都可以识别它。但是,只是详细说明,如果我们有一个未扩展另一个类的未知类,那么我们仍然可以使用以下方法获取最后定义的类:

$LastClass = array_pop(get_declared_classes());

因此,如果我们在定义后立即搜索它,我们总能找到所请求页面的类。有很多方法会破坏,但我怀疑大多数人都不会需要这种功能。