在 PHP 匿名函数中定义的 PHP 函数的范围是什么? [英] What is the scope of a PHP function defined within a PHP anonymous function?

查看:51
本文介绍了在 PHP 匿名函数中定义的 PHP 函数的范围是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

如果我这样做:

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

1) PHP 合法吗?还有……

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

3) lengthTest() 可以像这样被引用为 filter_var_array() 的回调方法吗?

$filterInstructionsArray ['fName' =>['过滤器' =>FILTER_CALLBACK],'标志' =>FILTER_REQUIRE_SCALAR,'选项' =>[$checkName, 'lengthTest']]];

4) 可以像这样将 lengthTest 引用为 filter_var_array() 的回调函数吗?

$filterInstructionsArray ['fName' =>['过滤器' =>FILTER_CALLBACK],'标志' =>FILTER_REQUIRE_SCALAR,'选项' =>'长度测试']];

<小时>

参考文献

PHP 手册对用户定义的函数有以下说明:

<块引用>

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

PHP 手册对匿名函数有以下说明:

<块引用>

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

感谢您花时间阅读、思考和回答我的问题.非常感谢.

解决方案

龟裂

从技术上讲,语法是正确的";(它不会产生致命错误)但 PHP 的语义使其在当前形式下实际上毫无意义.我们先来看几件事情,即 PHP 如何处理命名函数到变量的赋值:

php >echo shell_exec("php -v");PHP 5.4.16 (cli)(构建时间:2018 年 10 月 30 日 19:30:51)版权所有 (c) 1997-2013 PHP GroupZend Engine v2.4.0,版权所有 (c) 1998-2013 Zend Technologiesphp >function speak($arg) {echo "{$arg}\n";}php >函数给($arg){返回$arg;}php >$speak = speak(4);4php >$给 = 给(4);php >var_dump($speak);空值php >var_dump($give);整数(4)

函数本身在赋值时执行,其返回值(NULL 或其他)被赋值给变量.由于我们只是分配函数执行的返回值,因此尝试将此变量用作函数名是没有用的:

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

让我们将其与匿名函数(又名闭包")的赋值进行对比:

php >$min = 1;$max = 6;php >$checkName = 函数 ($value) 使用 ($min, $max) {php { echo "value: {$value}\n";php { echo "min: {$min}\n";php { echo "max: {$max}\n";php { };php >var_dump($checkName);对象(闭包)#1 (2) {[静态"]=>数组(2){[分钟"]=>整数(1)[最大"]=>整数(6)}[参数"]=>数组(1){[$value"]=>string(10) "<必需>";}}

与其他一些语言不同,闭包在 PHP 中由实际的对象表示.'use' 子句中的变量在闭包创建时被导入;当闭包被调用时,函数参数(即 $value)的被捕获(因此我们将其视为必需参数而不是静态值).闭包中引用的语义现在不值得考虑,但如果您想进一步阅读,goatgoat 的回答a href="https://stackoverflow.com/questions/10692817/whats-the-difference-between-closure-parameters-and-the-use-keyword">这个问题是一个很好的开始.>

这里的主要内容是闭包对 $checkName 的赋值并没有执行闭包本身.相反,$checkName 变成了一种别名".我们可以用名字来引用这个函数:

php >$checkName(你好,stackoverflow");值:你好 stackoverflow分钟:1最大:6php >

考虑到 PHP 在传递的函数参数数量方面的松散程度,零参数执行返回预期结果:

php >$checkName();价值:分钟:1最大:6php >

现在让我们更深入地定义一个函数:

php >函数 myOuterFunc($arg) {php { 函数 myInnerFunc($arg){php { echo "{$arg}\n";php { }php { }php >$myVal = myOuterFunc("Hello stackoverflow");php >var_dump($myVal);空值php >

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

php >函数 myOuterFunc($arg) {php { 函数 myInnerFunc($arg){php { echo "{$arg}\n";php { }php { myInnerFunc($arg);php { }php >$myVal = myOuterFunc("Hello stackoverflow");你好计算器溢出php >var_dump($myVal);空值php >

这让我们回到本质上你的问题:闭包内的命名函数怎么样?鉴于我们现在对函数执行的发现,我们可以生成一系列非常可预测的示例:

$min = 1;$max = 6;$checkName = 函数 ($value) 使用 ($min, $max) {function question(){echo "你好吗\n";}echo "value: {$value}\n";echo "min: {$min}\n";echo "max: {$max}\n";};php >$checkName(你好,stackoverflow");值:你好 stackoverflow分钟:1最大:6php >

正如预期的那样,闭包中命名函数的代码没有执行,因为我们没有显式调用它.

php >$min = 1;$max = 6;php >$checkName = 函数 ($value) 使用 ($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 { 问题();php { };php >$checkName(你好,stackoverflow");值:你好 stackoverflow分钟:1最大:6你好吗php >

显式调用内部函数效果很好,只要我们在调用它之前定义该函数:

php >$min = 1;$max = 6;php >$checkName = 函数 ($value) 使用 ($min, $max) {php { echo "value: {$value}\n";php { echo "min: {$min}\n";php { echo "max: {$max}\n";php { 问题();php { function question(){echo "How are you\n";}php { };php >$checkName(你好,stackoverflow");值:你好 stackoverflow分钟:1最大:6php >php >$min = 1;$max = 6;php >$checkName = 函数 ($value) 使用 ($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 { 问题();php { };php >$checkName(你好,stackoverflow");值:你好 stackoverflow分钟:1最大:6你好吗php >

那么就你的问题来说:

  1. 是的,这是合法的,您尝试的操作是可能的,但在当前形式下在语义上毫无意义.

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

3/4) 不是你想如何使用它,不.Closure 之外的任何东西都没有内部函数的任何概念;如果在调用您的闭包代码时,所述代码使用内部函数执行操作,那么它们将大放异彩.但是没有直接的方法来引用这些内部函数,就好像它们是在闭包的范围之外定义的一样.

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

希望这会有所帮助.

Question

If I do this:

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

1) Is it legal PHP? And ...

2) Is the function lengthTest() in the global namespace, or limited to just the $checkName Closure object? Would it be a private member, then?

3) Can lengthTest() be refereced as a callback method for filter_var_array() like this?

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

4) Can lengthTest be referenced as a callback function for filter_var_array() like this?

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


References

The PHP Manual says the following about user defined functions:

Any valid PHP code may appear inside a function, even other functions and class definitions. ... All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.

The PHP Manual says the following about anonymous functions:

Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses. Closures can also be used as the values of variables; PHP automatically converts such expressions into instances of the Closure internal class. Assigning a closure to a variable uses the same syntax as any other assignment, including the trailing semicolon:

Thank you for taking the time to read, think about, and respond to my question. I appreciate it very much.

解决方案

Cracks knuckles

Technically the syntax is "correct" (it won't generate a fatal error) but the semantics of PHP render it effectively meaningless in its current form. Let's look at a few things first, namely how PHP handles the assignment of named functions to variables:

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)

The function itself is executed upon assignment and its return value (NULL or otherwise) is assigned to the variable. Since we're only assigning the return value of a function's execution, trying to use this variable as a function name has no use:

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

Let's contrast this to the assignment of an anonymous function (a.k.a. a 'Closure'):

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

Unlike some other languages, a closure is represented in PHP by an actual Object. Variables inside the 'use' clause are imported at the time the Closure was created; function parameters (i.e. $value) have their values captured when the Closure is called (hence why we see it noted as a required parameter and not a static value). The semantics of references within Closures aren't worth considering right now but if you want further reading, goat's answer to this question is a great start.

The major takeaway here is that the Closure's assignment to $checkName did not execute the Closure itself. Instead, $checkName becomes a sort of "alias" we can use to reference this function by name:

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

Given how loose PHP is about the number of function parameters passed, a zero-parameter execution returns expected results:

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

Now let's take it another level deeper and define a function within a function:

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 >

By now this result should make sense. Functions do not execute unless explicitly called; just because we call myOuterFunc doesn't mean we execute any function code defined inside of it. That's not to say that we couldn't:

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 >

Which brings us back around to what is essentially your question: what about a named function inside of a Closure? Given what we've now discovered about function execution, we can generate a series of very predictable examples:

$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 >

As expected, the named function's code inside the Closure is not executed because we have not explicitly called it.

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 >

Explicitly calling the inner function works just fine, provided we define that function before we call it:

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 >

So to the point of your questions then:

  1. Yes it's legal and what you're attempting is possible but semantically meaningless in its current form.

  2. Any named functions inside the Closure definitely do not reside in the global namespace, they are within the scope of their defining Closure. FWIW, the term "members" typically refers to class variables (usually called "properties" in PHP). While Closures are an Object and let you duplicate the functionality of instance variables found within classes, they should not be confused or construed with classes in any way.

3/4) Not how you're trying to use it, no. Nothing outside of the Closure has any concept of the functions inside; if in calling your Closure code, said code performs operations using the inner functions, then they will see the light of day. But there is no immediate way to reference those inner functions as if they were defined outside of the Closure's scope.

In other words, the only way you'll get those inner functions to execute is if a) that code is specifically executed by the Closure's code and b) you execute said Closure code.

Hope this helps.

这篇关于在 PHP 匿名函数中定义的 PHP 函数的范围是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆