在 PHP 的全局命名空间的上下文中运行函数块

Posted

技术标签:

【中文标题】在 PHP 的全局命名空间的上下文中运行函数块【英文标题】:run function block in context of global namespace in PHP 【发布时间】:2011-04-20 11:54:59 【问题描述】:

因此,我想有一个自定义函数来要求库。比如:

define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) 
    $inc = E_ROOT.'/path/here/'.$fn.'.php';
    if($allowReloading)
        require $inc; // !!!
    else
        require_once $inc; // !!!

问题在于requirerequire_once 会将文件加载到函数的命名空间中,这对函数库、类库等没有帮助。那么有没有办法做到这一点?

(完全避免 requirerequire_once 是可以的,只要它不使用 eval,因为它在很多主机上被禁止。)

谢谢!

【问题讨论】:

如果它真的是一个,而不是模块,那么它包含在什么范围内都没有关系 我的意思是库通常代表一个只包含函数/类的文件 【参考方案1】:

从技术上讲,include() 的作用就像您在 PHP 中插入包含脚本的文本一样。因此:

includeMe.php:
<?php
    $test = "Hello, World!";
?>

includeIt.php:
<?php
    include('includeMe.php');
    echo $test;
?>

应该与以下内容完全相同:

<?php
    /* INSERTED FROM includeMe.php */
    $test = "Hello, World!";
    /* END INSERTED PORTION */
    echo $test;
?>

意识到这一点,创建一个动态包含文件的函数的想法与将动态代码放在一起一样有意义(并且容易做到)。有可能,但会涉及很多元变量。

我会研究 PHP 中的 Variable Variables 以及用于将变量引入全局范围的 get_defined_vars 函数。这可以通过以下方式完成:

<?php
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) 

    $prev_defined_vars = get_defined_vars();

    $inc = E_ROOT.'/path/here/'.$fn.'.php';
    if($allowReloading)
        require $inc; // !!!
    else
        require_once $inc; // !!!

    $now_defined_vars = get_defined_vars();

    $new_vars = array_diff($now_defined_vars, $prev_defined_vars);

    for($i = 0; $i < count($new_vars); $i++)
        // Pull new variables into the global scope
        global $$newvars[$i];
    

?>

使用require()require_once() 代替e_load() 可能更方便

请注意,函数和常量始终位于全局范围内,因此无论在何处定义它们都应该可以从代码中的任何位置调用。

一个例外是在类中定义的函数。这些只能在类的命名空间内调用。

编辑:

我只是自己测试了这个。函数在全局范围内声明。我运行了以下代码:

<?php
function test()
    function test2()
        echo "Test2 was called!";
    


//test2(); <-- failed
test();
test2(); // <-- succeeded this time
?>

所以该函数仅在test() 运行后才定义,但该函数随后可从test() 外部调用。因此,您唯一需要通过我之前提供的脚本将变量拉入全局范围。

【讨论】:

【参考方案2】:
require_once E_ROOT.$libName.'.php';

亲吻

【讨论】:

我只希望 libName 不是来自用户输入 我的意思是 $libName 来自函数。而且,是的——这行得通。但是对于说 10 个不同的文件,不在一个文件中是很多重复。 对比e_load('libName') @aharon 您输入问题的次数已经增加了 10 倍。有时我们为了轻松而把事情复杂化 我不理解对 e_load 函数的需求,除非您希望用户能够指定要包含的文件,在这种情况下,您需要解析他们的输入以确保他们不是' t 包括任何危险文件。虽然这是可能的。您只需要将变量拉入全局范围。【参考方案3】:

而不是这样做......

$test = "Hello, World!";

...您可以考虑这样做...

$GLOBALS[ 'test' ] = "Hello, World!";

这在本地函数上下文和全局包含上下文中都是安全且一致的。在视觉上提醒读者您期望 $test 成为全局变量可能无害。如果您的库中拖入了大量全局变量,则可能有理由将其包装在一个类中(那么您将受益于 spl_autoload_register 哪种方式可以完成您正在做的事情)。

【讨论】:

以上是关于在 PHP 的全局命名空间的上下文中运行函数块的主要内容,如果未能解决你的问题,请参考以下文章

命名空间

*args **kwargs函数的命名空间。

04. 命名空间,函数重载,内联

04. 命名空间,函数重载,内联

函数进阶

Python学习:函数进阶