2010-12-22 105 views
4
//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获取包含文件的名称空间

///编辑

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

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

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

+0

是否可以使用关键字“use”IE:“use foo”。对不起 - 不知道这是否会起作用 – cdnicoll 2010-12-22 18:43:12

回答

15

不可以,但你可以诱骗轮这样:

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

以及读取出来:

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

学到了新的东西。 – 2010-12-22 18:59:58

+4

n.b.从包含中返回的值可能被认为是不好的做法,因为它不是传统的行为。 – 2013-11-15 22:43:21

0

我制定了相当费力的手工方式做到这一点。

像在上面讨论的过程本身很简单:

  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 
    } 
} 
?> 
+1

虽然你的答案确实提供了一些有用的东西,但转向Zend只是为了做到这一点是矫枉过正的。只用PHP本身,有很多方法可以更快地处理这个问题。在转向框架之前,请考虑您自己的知识和能力;) – Digitalis 2012-12-03 14:49:45

5

那么,你可以扫描类命名空间。它包含命名空间。这是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

2

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

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; 
} 

而且你不会限制在文件的末尾返回一些可以退出或返回指令的文件。