【问题标题】:php get namespace of included filephp 获取包含文件的命名空间
【发布时间】:2011-05-29 14:00:38
【问题描述】:
//file foo.php
<?php
namespace foo;
class foo{
    function __construct(){
        echo "hello";
    }
}
?>

//file index.php
<?php
require_once("foo.php");
echo __NAMESPACE__;
?>

我的问题是,从我的 index.php 文件中,是否可以在不读取文件内容并对其执行正则表达式的情况下知道 foo.php 的命名空间是什么?这似乎是很多开销。

///编辑

我真的很希望能够将命名空间动态添加到包含的文件中。

<?php
namespace dynamic;
require_once("foo.php");
echo __NAMESPACE__;
?>

我想允许第三方插件,但 php 命名空间似乎很糟糕。我不希望插件编辑器必须创建命名空间。

【问题讨论】:

  • 是否可以只使用关键字“use” IE:“use foo”。抱歉——不确定这是否可行

标签: php namespaces


【解决方案1】:

如果你知道这个文件,你可以简单地从它中提取命名空间:)。

function extract_namespace($file) {
    $ns = NULL;
    $handle = fopen($file, "r");
    if ($handle) {
        while (($line = fgets($handle)) !== false) {
            if (strpos($line, 'namespace') === 0) {
                $parts = explode(' ', $line);
                $ns = rtrim(trim($parts[1]), ';');
                break;
            }
        }
        fclose($handle);
    }
    return $ns;
}

并且您将不会被限制在文件末尾返回一些可以从退出或其他返回指令中破坏的内容。

【讨论】:

    【解决方案2】:

    好吧,你可以扫描类命名空间。它包含命名空间。这是 PHPUnit 的做事方式。所以即:

    $namespaces = get_current_namespaces();
    
    include 'plugin/main.php';
    
    $newNamespaces = get_current_namespaces(); 
    array_diff($namespaces, $newNamespaces)
    

    这里是如何实现get_current_namespaces()is it possible to get list of defined namespaces

    【讨论】:

    • 我不是在争论,但是这样,您将只能捕获“新”命名空间。
    • 你是对的@Nick。它应该是函数stackoverflow.com/a/5227353/181664 的一个变体,用于检测所有新定义的类并从中删除命名空间。
    【解决方案3】:

    我想出了相当费力的手动方法。

    就像上面讨论的那样,过程本身很简单:

    1. 获取每个文件的文件列表。现在对于每个文件:
    2. 创建一个随机命名空间 id
    3. 修剪文件并替换第一个开始标签
    4. 将命名空间 id 和开始标签添加到文件中
    5. 写入临时文件
    6. 导入临时文件
    7. 做任何需要的反射然后清理

    我有一个例子,这里有一些 zend.... 可能不是最有效的,但它有效。

    <?php
    //first setup zend
    set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__)."/../zend/library/");
    require_once 'Zend/Loader/Autoloader.php';
    $loader = Zend_Loader_Autoloader::getInstance();
    $loader->registerNamespace(dirname(__FILE__)."/../zend/library/");
    
    //include my extender class
    class Zend_Reflection_File_WithNamespace extends Zend_Reflection_File {
        public function getFunctionsWithNamespace($namespace = '', $reflectionClass = 'Zend_Reflection_Function')
        {
            $functions = array();
            foreach ($this->_functions as $function) {
                $newName = $namespace . "\\" . $function;
                $instance = new $reflectionClass($newName);
                if (!$instance instanceof Zend_Reflection_Function) {
                    require_once 'Zend/Reflection/Exception.php';
                    throw new Zend_Reflection_Exception('Invalid reflection class provided; must extend Zend_Reflection_Function');
                }
                $functions[] = $instance;
            }
            return $functions;
        }
    }
    
    //find file(s)
    $startDir = 'hello/';
    //$tempDir = 'php://temp/resource=';
    $tempDir = 'temp/';
    $fileList = scandir($startDir);
    
    function ppPrintR($data) {
        echo "<pre>";
        print_r($data);
        echo "</pre>";
    }
    
    //Now loop through each file, first writing to temp, including and then testing
    foreach ($fileList as $key => &$fileItem) {
        if (is_file($startDir . $fileItem)) {
            //Take file and convert it
            $findDir = $startDir . $fileItem;
            echo $startDir . $fileItem;
    
            $inContents = file_get_contents($findDir); 
            $randIden = 'm' . preg_replace('/\.|\s/', '', microtime());
    
            //Replace the <?[php] at the start of the file with <? namespace xyz;
            $inContents = trim($inContents);
            $addString = 'namespace ' . $randIden . '; ';
    
            $longTagPos = strpos($inContents,'<?php');
            $shortTagPos = strpos($inContents,'<?');
    
            if ($longTagPos !== false && $longTagPos < 10) {
                $inContents = str_replace('<?php', '', $inContents);
                $addString = '<?php ' . $addString;
            }
            else if ($shortTagPage !== false && $longTagPos < 10) {
                $inContents = str_replace('<?', '', $inContents);
                $addString = '<? ' . $addString;
            }
            $outContents = $addString . $inContents;
    
            //Now write and require new temp file
            $tempItem = $tempDir . $fileItem;
            file_put_contents($tempItem, $outContents);
            require($tempItem);
    
            //Now do normal things
            $reflectedFile = new Zend_Reflection_File_WithNamespace($tempItem);
            echo 'Before<br/>';
            $functions = $reflectedFile->getFunctionsWithNamespace($randIden);
            echo 'After<br/>';
    
            //Now foreach function, read params and consider execution
            foreach($functions as &$functionItem) {
                echo $functionItem->name . "<br/>";
                $functionParams = $functionItem->getParameters();
                ppPrintR($functionParams);
            }
    
            //FIXME should clean here
        }
    }
    ?>
    

    【讨论】:

    • 尽管您的答案确实提供了一些有用的东西,但仅仅为了做到这一点而求助于 Zend 是过分的。仅使用 PHP 本身,就有多种方法可以更快地处理这个问题。在转向框架之前,请考虑您自己的知识和能力;)
    • 没错,我只是在整个项目中使用了zend,所以实际上并没有什么额外的东西。喜欢看到非框架解决方案。
    【解决方案4】:

    没有。但是你可以这样欺骗它:

    //file foo.php
    <?php
      namespace foo;
      //...
      return __NAMESPACE__;  // must be last line
    ?>
    

    为了阅读它:

    //file index.php
    <?php
      $ns = require_once("foo.php");
    

    【讨论】:

    • n.b.从包含返回值可能被视为不好的做法,因为它不是传统行为。
    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-04
    • 2011-07-24
    • 1970-01-01
    • 2014-09-06
    • 2014-04-26
    相关资源
    最近更新 更多