在PHP匿名函数中定义的PHP函数的范围是什么?

时间:2017-02-23 05:56:03

标签: php function scope anonymous-function

问题

如果我这样做:

$checkName = function ($value) use ($min, $max)  {
    function lengthTest($string, $min, $max)
    {
        $length = mb_strlen($string, 'UTF-8');
        return ($length >= $min) && ($length <= $max);
    }
};

1)这是合法的PHP吗?而且......

2)函数lengthTest()是全局命名空间中的,还是仅限于$checkName Closure个对象?那么它会成为私人会员吗?

3)可以将lengthTest()作为filter_var_array()的回调方法参考吗?

$filterInstructionsArray [
    'fName'   => ['filter' => FILTER_CALLBACK],
    'flags'   => FILTER_REQUIRE_SCALAR,
    'options' => [$checkName, 'lengthTest']]
];

4)可以lengthTest引用filter_var_array()作为$filterInstructionsArray [ 'fName' => ['filter' => FILTER_CALLBACK], 'flags' => FILTER_REQUIRE_SCALAR, 'options' => 'lengthTest'] ]; 的回调函数吗?

var dps = JSON.stringify(ReportArray[i].displaySettings);
dps = dps.slice(1, -1)
dps = dps.replace('"', "'").replace('"', "'");

参考

PHP手册中提到了以下user defined functions

  

任何有效的PHP代码都可能出现在函数内部,甚至是其他函数   和类定义。 ... PHP中的所有函数和类都有   全局范围 - 即使它们可以在函数外部调用它们   内部定义,反之亦然。

PHP手册中提到了以下anonymous functions

  

匿名函数,也称为闭包,允许创建   没有指定名称的函数。它们最有用   回调参数的值,但它们有许多其他用途。关闭   也可以用作变量的值; PHP自动   将这些表达式转换为Closure内部的实例   类。为变量分配闭包使用与any相同的语法   其他任务,包括尾随分号:

感谢您抽出宝贵时间阅读,思考并回答我的问题。我非常感激。

1 个答案:

答案 0 :(得分:1)

裂纹指关节

从技术上讲,语法是“正确的”(不会产生致命错误),但是PHP的语义使其在当前形式上实际上毫无意义。首先让我们看一些事情,即PHP如何处理命名函数到变量的分配:

php > echo shell_exec("php -v");
PHP 5.4.16 (cli) (built: Oct 30 2018 19:30:51)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

php > function speak($arg) {echo "{$arg}\n";}
php > function give($arg) {return $arg;}
php > $speak = speak(4);
4
php > $give = give(4);
php > var_dump($speak);
NULL
php > var_dump($give);
int(4)

函数本身在分配时执行,并且其返回值(NULL或其他)分配给变量。由于我们仅分配函数执行的返回值,因此尝试将此变量用作函数名称没有用:

php > $speak(4);
php > $give(4);
php >

让我们将此与匿名函数(也称为“关闭”)的分配进行对比:

php > $min = 1; $max = 6;
php > $checkName = function ($value) use ($min, $max) {
php {   echo "value: {$value}\n";
php {   echo "min: {$min}\n";
php {   echo "max: {$max}\n";
php { };
php > var_dump($checkName);
object(Closure)#1 (2) {
  ["static"]=>
  array(2) {
    ["min"]=>
    int(1)
    ["max"]=>
    int(6)
  }
  ["parameter"]=>
  array(1) {
    ["$value"]=>
    string(10) "<required>"
  }
}

与其他一些语言不同,闭包在PHP中由实际的Object表示。 “使用”子句中的变量是在创建封包时导入的;函数参数(即$ value)具有,当闭包被称为时被捕获(因此我们将其名称记为必需参数,而不是静态值)。闭包中引用的语义目前不值得考虑,但是如果您想进一步阅读,goatthis问题的答案是一个很好的开始。

这里的主要要点是,闭包对$ checkName的分配没有执行闭包本身。相反,$ checkName成为一种“别名”,我们可以使用它来通过名称引用此函数:

php > $checkName("hello stackoverflow");
value: hello stackoverflow
min: 1
max: 6
php >

鉴于PHP传递的函数参数数量有多宽松,零参数执行将返回预期结果:

php > $checkName();
value:
min: 1
max: 6
php >

现在让我们更进一步,在函数中定义一个函数:

php > function myOuterFunc($arg) {
php {   function myInnerFunc($arg){
php {     echo "{$arg}\n";
php {   }
php { }
php > $myVal = myOuterFunc("Hello stackoverflow");
php > var_dump($myVal);
NULL
php >

现在,这个结果应该是有意义的。除非明确调用,否则函数不会执行;仅仅因为我们调用myOuterFunc并不意味着我们执行其中定义的任何功能代码。并不是说我们不能:

php > function myOuterFunc($arg) {
php {   function myInnerFunc($arg){
php {     echo "{$arg}\n";
php {   }
php {   myInnerFunc($arg);
php { }
php > $myVal = myOuterFunc("Hello stackoverflow");
Hello stackoverflow
php > var_dump($myVal);
NULL
php >

这使我们回到本质上是您的问题所在:闭包内部的命名函数如何?鉴于我们现在发现的有关函数执行的知识,我们可以生成一系列非常可预测的示例:

$min = 1; $max = 6;
$checkName = function ($value) use ($min, $max) {
  function question(){echo "How are you\n";}
  echo "value: {$value}\n";
  echo "min: {$min}\n";
  echo "max: {$max}\n";
};
php > $checkName("Hello stackoverflow");
value: Hello stackoverflow
min: 1
max: 6
php >

按预期的那样,由于我们尚未显式调用闭包中的命名函数,因此不会执行该函数。

php > $min = 1; $max = 6;
php > $checkName = function ($value) use ($min, $max) {
php {   function question(){echo "How are you\n";}
php {   echo "value: {$value}\n";
php {   echo "min: {$min}\n";
php {   echo "max: {$max}\n";
php {   question();
php { };
php > $checkName("Hello stackoverflow");
value: Hello stackoverflow
min: 1
max: 6
How are you
php >

显式调用内部函数可以正常工作,前提是我们在之前定义了该函数:

php > $min = 1; $max = 6;
php > $checkName = function ($value) use ($min, $max) {
php {   echo "value: {$value}\n";
php {   echo "min: {$min}\n";
php {   echo "max: {$max}\n";
php {   question();
php {   function question(){echo "How are you\n";}
php { };
php > $checkName("Hello stackoverflow");
value: Hello stackoverflow
min: 1
max: 6
php >

php > $min = 1; $max = 6;
php > $checkName = function ($value) use ($min, $max) {
php {   echo "value: {$value}\n";
php {   echo "min: {$min}\n";
php {   echo "max: {$max}\n";
php {   function question(){echo "How are you\n";}
php {   question();
php { };
php > $checkName("Hello stackoverflow");
value: Hello stackoverflow
min: 1
max: 6
How are you
php >

那么到您要问的问题:

1)是的,这是合法的,您正在尝试的事情是可能的,但从目前的形式看,它在语义上毫无意义。

2)闭包内部的任何命名函数绝对不驻留在$ global命名空间中,它们在其定义的闭包范围内。 FWIW,术语“成员”通常是指类变量(在PHP中通常称为“属性”)。闭包是一个对象,可以让您复制在类中找到的实例变量的功能,但不应以任何方式将它们与类混淆或解释。

3/4)不是您要如何使用它,不是。闭包之外没有任何关于内部功能的概念。如果在调用您的Closure代码时,所述代码使用内部函数执行操作,那么它们将成为现实。但是,没有立即的方法可以引用这些内部函数,就像在闭包的范围之外定义它们一样。

换句话说,要让这些内部函数执行,唯一的方法是:a)代码是由Closure的代码专门执行的,并且b)您执行了所述Closure的代码。

希望这会有所帮助。