我想从一个方法中包含/要求一个包含多个功能的文件。我的目标是使如此包含的函数仅在相应方法的范围内可用,而在调用范围内不可用。这在PHP中可行吗?
例如在下面的最小示例中,我希望foo()
仅在方法buzz()
中可用,而不能从周围的范围中使用(不幸的是)。
// foo.php
<?php
function foo()
{
return "foo";
}
// bar.php
<?php
class Bar
{
public function buzz()
{
require_once("foo.php");
return foo();
}
}
$bar = new Bar();
// should work
echo $bar->buzz();
// should not work
echo foo();
常规任务是将旧代码库中的功能包装到Symfony服务的方法中。只有通过调用相应的方法才能访问旧功能。因此,旧功能不应在全局范围内。
一个主要限制是foo.php
中的功能是我无法修改的旧版代码库的一部分。
答案 0 :(得分:0)
我的目标是使如此包含的功能仅在 各自方法的范围,不在调用范围之内。这是 可能在PHP中使用?
不直接。不是类方法的未命名函数始终是全局范围。如果您只是不希望它们在全局范围内,则只需在名称空间中声明它们即可。但是,它们仍然可以在任何范围内调用。
如果那还不够,那么有(相当丑陋)的选择。由于在函数中定义的变量仅对该函数可用,因此您可以通过使用分配给变量的匿名函数来近似尝试执行的操作。这些将在功能结束时有效消失。
foo.php
$function = function()
{
return "foo";
};
bar.php
class Bar
{
public function buzz()
{
require_once 'foo.php';
$function();
}
}
答案 1 :(得分:0)
如果想发挥创意,可以在需要之前重写文件以包含名称空间声明。这可能看起来像这样:
function wrapInNamespace(string $req): string
{
// Namespaces have to start with a letter, unique IDs might not
$tempNamespace = 'a' . uniqid();
$namespaceDeclaration = sprintf("namespace %s;\r\n", $tempNamespace);
$lines = file($req);
array_splice($lines, 1, null, $namespaceDeclaration);
$temp = tmpfile();
fwrite($temp, implode('', $lines));
require_once(stream_get_meta_data($temp)['uri']);
fclose($temp);
return $tempNamespace;
}
array_splice
行在文件的第二行添加了动态生成的名称空间声明,然后我们将其返回,以便您以后可以引用这些函数。这是通过临时文件完成的。
丑陋的部分是,在实际调用它们时,您需要分配一个命名空间标识符,因为据我所知,不可能在一行上的动态命名空间中调用函数(我很高兴被告知不同):
class Bar
public function buzz()
{
$tempNamespace = wrapInNamespace('foo.php');
$func = "\\$tempNamespace\\foo";
$func();
}
}
所有内容放在一起,这意味着您可以执行以下操作:
echo (new Bar)->buzz();
# foo
foo();
# PHP Fatal error: Uncaught Error: Call to undefined function foo() ...
这全部要求您的文件在第一行以<?php
开头,并且不包含任何其他名称空间声明。使用同一文件两次调用wrapInNamespace
将为您提供文件的两个完全不同的版本-只要您不将命名空间从buzz
方法中泄漏出去,就不能从其他任何地方调用它。这是否有用将取决于您要包括的源文件的确切范围。如果它们只是其他全局函数的集合,则可以很好地完成工作。如果它们还包含过程代码,它将没有太大用处。