【问题标题】:PHP by-reference parameters and default nullPHP 引用参数和默认 null
【发布时间】:2010-09-21 18:39:31
【问题描述】:

假设我们有一个像

这样的方法签名
public static function explodeDn($dn, array &$keys = null, array &$vals = null,
    $caseFold = self::ATTR_CASEFOLD_NONE)

我们可以通过省略$dn之后的所有参数来轻松调用该方法:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com');

我们也可以调用3个参数的方法:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v);

并带有 4 个参数:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

但是为什么不能调用例如下面的参数组合的方法:

$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, null, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', null, $v);

null 传递给方法和依赖默认值有什么区别?该约束是否写在手册中?可以绕开吗?

【问题讨论】:

    标签: php null pass-by-reference


    【解决方案1】:

    正如@aschmecher 在评论中指出的那样 @Szczepan's answer here,执行func($var = null) 会生成严格标准通知。

    一个解决方案

    这是一种不会产生任何此类警告的方法:

    <?php
    error_reporting(E_ALL | E_STRICT);
    
    function doIt(&$x = null) {
        if($x !== null) echo "x not null: $x\n";
        $x = 2;
    }
    
    function &dummyRef() {
        $dummyRef = null;
        return $dummyRef;
    }
    
    doIt(dummyRef());
    
    doIt(dummyRef());
    

    说明

    代替传递变量,我们传递返回引用的函数的结果。对doIt(dummy()) 的第二次调用是为了验证引用$dummy 值在调用之间是否保持不变。这与显式创建变量不同,后者需要记住清除所有累积值:

    $dummyRef = null;
    doIt($dummyRef);
    doIt($dummyRef); // second call would print 'x not null: 2'
    

    应用程序

    所以在 OP 的示例中,它将是:

    $dn = Zend_Ldap_Dn::explodeDn(
        'CN=Alice Baker,CN=Users,DC=example,DC=com',
        $k,
        dummyRef(),
        Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER
    );
    

    其他注意事项

    我可能担心的一件事是这种方法是否会造成内存泄漏。以下测试表明它没有:

    <?php
    function doItObj(&$x = null) {
        if(gettype($x) !== "object") echo "x not null: $x\n";
        $x = 2;
    }
    
    function &dummyObjRef() {
        $dummyObjRef = new StdClass();
        return $dummyObjRef;
    }
    
    echo "memory before: " . memory_get_usage(true) .  "\n";
    
    for($i = 0; $i < 1000000; $i++) {
        doItObj(dummyObjRef());
    }
    
    echo "memory after: " . memory_get_usage(true) . "\n";
    
    echo "\n$i\n";
    

    在我的系统上(使用 PHP 5.6.4),对 memory_get_usage 的两次调用都显示为 ~ 262 KB。

    【讨论】:

      【解决方案2】:

      如果要显式传递 NULL,则必须为 by-ref 参数创建一个虚拟变量,但不必在单独的行上创建该变量。您可以将 $dummy=NULL 之类的赋值表达式直接用作函数参数:

      function foo (&$ref = NULL) {
      
          if (is_null($ref)) $ref="bar";
          echo "$ref\n";        
      }
      
      foo($dummy = NULL); //this works!
      

      【讨论】:

      • 这给了我严格模式警告:PHP Strict Standards: Only variables should be passed by reference in (snip)/test.php on line 9
      • 如果变量$dummy还不存在,那么当你像这样传递它时它将为空:foo($dummy)。如果您希望重用该 dummy 变量,并且想要一个单行,您可以始终 a) 确保它不会在您的函数内从 null 更改或 b) 执行此操作:($dummy = null) and foo($dummy).
      【解决方案3】:

      我自己才发现这个,我很震惊 o_O!

      PHP documentation 是这么说的:

      function makecoffee($type = "cappuccino")
      {
          return "Making a cup of $type.\n";
      }
      echo makecoffee(); // returns "Making a cup of cappuccino."
      echo makecoffee(null); // returns "Making a cup of ."
      echo makecoffee("espresso"); // returns "Making a cup of espresso."
      

      我原以为makecoffee(null) 会返回“制作一杯卡布奇诺”。 我使用的一种解决方法是检查函数内部是否参数为空:

      function makecoffee($type = null)
      {
          if (is_null($type)){ 
             $type = "capuccino";
          }
          return "Making a cup of $type.\n";
      }
      

      现在makecoffee(null) 返回“制作一杯卡布奇诺”。

      (我意识到这实际上并不能解决与 Zend 相关的问题,但它可能对某些人有用......)

      【讨论】:

        【解决方案4】:

        @托马拉克

        实际上,默认值会创建一个不涉及任何引用的变量。这是您在传递某些东西时根本无法启动的东西。

        我发现可以说明原因的是以下示例(我没有测试):

        function foo (&$ref = NULL) {
          $args = func_get_args();
          echo var_export($ref, TRUE).' - '.var_export($args, TRUE);
        }
        $bar = NULL;
        foo();     // NULL - array()
        foo($bar); // NULL - array(0 => NULL)
        

        在我看来,PHP 应该提供一种不传递某些参数的方法,例如使用
        foo($p1, , , $p4); 或类似语法而不是传递 NULL。
        但它没有,所以你必须使用虚拟变量。

        【讨论】:

        • 这是一个有趣的语法想法......我个人希望看到在调用中放置命名函数参数的能力,例如doSomething($var1, @optionalParam4=$var2);.
        【解决方案5】:

        只是为了确认Tomalak 所说的here

        以下作品:

        $k=array();
        $v=null;
        $dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v, 
            Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);
        

        不好 - 但解释清楚易懂。

        【讨论】:

          【解决方案6】:

          这是因为你不能有对 null 的引用。

          您可以引用包含 null 的变量 - 这正是默认值的作用。或者您可以将 null 作为文字值传入 - 但由于您需要一个 out 参数,因此这里不可能。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-01-24
            • 1970-01-01
            • 2011-08-23
            • 1970-01-01
            • 2021-02-05
            • 2012-06-14
            • 2016-06-12
            • 1970-01-01
            相关资源
            最近更新 更多