【问题标题】:Function assign a parameter that isn't null函数分配一个不为空的参数
【发布时间】:2014-05-25 03:26:48
【问题描述】:

这是我上一个问题的后续问题。

Run a function without a parameter but needed a variable outside of the function - PHP

我收到了这个答案

function foo($arg1 = null, $arg2 = null) {
    // if they are not set retrieve from a session
    $arg1 = ($arg1 !== null) ? $arg1 : $_SESSION['arg1'];
   // rinse repeat.
}

所以我想,也许我可以通过防止在每个函数上调用相同的变量来减少代码行。

我想出了这个。

function foo($arg1 = $_SESSION['user_id'], $arg2 = $_SESSION['campaign_id']) {
     //do something
}

很遗憾,我收到了这个错误。

Parse error: syntax error, unexpected T_VARIABLE

这是有原因的吗?我只是用一个有值的变量替换了 null

有没有什么方法可以给一个参数已经有值的函数赋值,而不是给一个空值赋值?

附言

我正在尝试使用echo $campaign->getName()输出数据,所以调用函数时没有提供参数。

所以我试图调用类似这样的函数

function foo($arg1 = $_SESSION['user_id'], $arg2 = $_SESSION['campaign_id']) {
     //do something
}

如果有任何方法可以做到这一点,而无需一遍又一遍地调用同一个变量。

任何帮助将不胜感激。 :)

【问题讨论】:

  • 请链接到您之前的问题,因为我们不知道您在说什么。 (edit你的问题)
  • 你去,已经把它放进去了。:D
  • 在特定情况下,例如 $_SESSION['user_id'] - 即在脚本执行期间应保持不变的值 - 您可以将其定义为常量define('APP_USER_ID', $_SESSION['user_id']); 然后常量可以用作默认值function foo($arg = APP_USER_ID) {}。虽然这似乎是一个有吸引力的选择(并且在现实世界中是相当普遍的做法),但出于依赖全局状态的原因,建议这样做,如下面的几个答案所述。

标签: php function parameters null variable-assignment


【解决方案1】:

tl;博士

不要尝试(它甚至没有像您看到的那样真正起作用),使用正确的 DI(依赖注入)并将您的外部(全局)变量作为参数传递:

// functions should be deterministic — require the arguments in favour of using dynamic defaults
function foo($arg1 /* require it */, $arg2 = 1 /* static scalars as default is no problem */) {
    // your code
}
foo($_SESSION["user_id"]); // always pass dynamic arguments, don't fetch them in the function

简介

不可能使用其他任何东西作为所谓的静态标量的默认值。这些是文字(字符串、整数等)、常量和(从 PHP 5.6 开始)对这些文字/常量的操作。

所以...

两年多前我有同样的好主意并提交了错误报告...https://bugs.php.net/bug.php?id=60544

今天我认为这不是一个好主意。默认值在语言中应该是静态的。我怀疑那些设计 PHP 的人没有他们的理由。

但还是有办法的……

你如何可以做到(不推荐)

这里唯一的解决方法是使用常量。

function foo($arg = ARG) {
    var_dump($arg);
}

在你确定值不会再改变的那一刻,在第一次调用函数之前定义常量:

define("ARG", $_SESSION["user_id"]);

然后您可以稍后通过foo(); 调用它。

这可能是由于这里对常量的惰性求值。

此方法的缺点是您必须定义一次常量,然后在脚本运行时的其余部分将保持不变。

但我仍然强烈不推荐。它很hackish并且有很大的缺点。

你如何做得更好

您已经向我们展示了如何做到这一点:

$arg1 = ($arg1 !== null) ? $arg1 : $_SESSION['arg1'];

这绝对是正确的方法。如果你真的想做的话。

但你仍然不应该那样做。您正在从函数访问全局范围(超全局)。

你应该如何

语言设计者没有实现这种可能性是有原因的,这也是为什么我们不应该尝试通过函数中的常量或全局范围访问以任何方式规避这种可能性的原因。

您确实应该正确使用依赖注入并通过参数将外部(全局)值传递给函数。 (参见 tl;dr 部分中的示例)

您提出的这种类型的代码很容易导致难以调试的代码,因为人们可能不希望真正的函数访问全局状态。

这就是为什么函数对于给定的输入应该具有确定性的输出(除非它们被明确认为是非确定性的,例如读取文件的函数),这极大地提高了可测试性和可移植性。

【讨论】:

    【解决方案2】:

    你不能。

    您只能将 literals 分配给函数默认值,即在运行时无法更改的常量值。这意味着,"actual strings"、数字 (42)、硬编码数组 ([1, 2, 3])、NULL。而不是 $variablesfunction() {} 或其他任何可能在运行时更改的内容。

    你也不应该。

    如果你的函数依赖于一个用户 ID 和一个活动 ID,你应该将它们传递到你的函数中,而不是依赖它们在 SESSION 中,因为你不知道它们是否真的在里面!

    不要依赖全局变量。


    为什么不将参数传递给函数?它需要它们,不是吗?您是否希望以下函数在没有参数的情况下工作?

    add($x, $y)
    

    仅仅因为这些参数来自 SESSION、数据库或其他世界?

    没有。该函数需要两个参数,因此,它应该要求并且给定两个参数。

    【讨论】:

    • 绝对是更好的答案。坚持基础。提供您的变量,或使用文字默认值。
    【解决方案3】:

    我有一个坏消息要告诉你,较短的形式并不总是更好。这主要是因为您将 $_SESSION 值称为常量,这并不是很好。 一个好的、可靠的代码会更长,因为所有的检查和验证都有助于避免不必要的错误。这基本上就是你需要做的:

    function foo($arg1 = null, $arg2 = null) {
        // if condition
        if (!$arg1 && isset($_SESSION['arg1']))
            $arg1 = $_SESSION['arg1'];
    
        // tenary condition
        $arg2 = (!$arg2 && isset($_SESSION['arg2'])) ? $arg2 : $_SESSION['arg2'];
    }
    

    如果你真的想,你可以寻找一些能将这段代码缩短几个字母的东西,但实际上并没有太大的不同。所有这些验证都是必须,不应被忽视。

    【讨论】:

      【解决方案4】:

      查看您之前的问题,我猜您有许多需要广告系列 ID 和用户 ID 的方法。我建议您将活动 ID 和用户 ID 传递给 Campaign 类的构造函数。然后你可以调用任何方法并且总是可以访问它们:

      <?php
      
      $campaign = new Campaign($db, $_SESSION['user_id'], $_SESSION['campaign_id']);
      
      class Campaign {
        private $db;
        private $user_id;
        private $campaign_id;
      
        public function __construct($db, $user_id, $campaign_id) {
          $this->db = $db;
          $this->user_id = $user_id;
          $this->campaign_id = $campaign_id;
        }
      
        public function getName() {
          $query = $this->db->prepare("SELECT name FROM campaign WHERE campaign_id = :campaign_id AND user_id = :user_id");
          $status = $query->execute(array(':campaign_id' => $this->campaign_id, ':user_id' => $this->user_id));
          return ($query->rowCount() == 1) ? $query->fetchObject()->name : false;
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-25
        • 2014-10-12
        • 2018-11-13
        • 1970-01-01
        • 2014-05-29
        • 2021-04-23
        • 2022-01-11
        相关资源
        最近更新 更多