【问题标题】:Static array in PHP function not workingPHP函数中的静态数组不起作用
【发布时间】:2018-10-09 14:15:47
【问题描述】:

PHP - 使用静态数组变量测试一个简单的函数。我假设函数中声明的静态变量会使其在函数之外可用。

这个函数只需要一条消息并将它添加到errors[]数组中,然后就可以在函数之外使用这个errors[]列表。

我收到错误消息: “注意:未定义的变量:第 10 行中的错误......”

第 10 行的代码是“print_r($errors);”

function addErrors($errmessage){
    static $errors = array();
    $errors[] = $errmessage; 
}
addErrors('test1');
addErrors('test2');
print_r($errors);

感谢您的意见!

【问题讨论】:

标签: php static


【解决方案1】:

$errors是函数内部的静态变量,不能从全局范围内访问。

这是一个如何实现你想要做的事情的例子:

PHP 7
<?php

/**
* @param string|null the error message to add or null
* @return array|null returns all errors if provided with null 
*/
function errors($error = null) {
   static $errors = [];
   if($error !== null) {
       $errors[] = $error;
       return null;
   } else {
       return $errors;
   }
}

errors('Error !');
errors('Another !');
print_r(errors());

PHP 7 >= :

<?php

function errors(string $error = null): ?array {
   static $errors = [];
   if($error !== null) {
       $errors[] = $error;
       return null;
   } else {
       return $errors;
   }
}

errors('Error !');
errors('Another !');
print_r(errors());

【讨论】:

  • 谢谢!但是,您的示例代码会产生语法错误:“意外的 ':',期望 '{' in...”。但是当我稍微修改它时,它工作正常: function errors($error = null){ static $errors = []; if($error !== null) { $errors[] = $error;返回空值; } 其他 { 返回 $errors; } }
  • 您使用的是什么 php 版本?我的代码是有效的 php 7.0 代码,但是我要为 php 5 添加另一个代码。*
  • 我正在使用 php 5.5.15... 也许这就是它给出语法错误的原因?你能告诉我“?array”代码的用途吗?
  • 我强烈建议您升级到 php 7.2,它的速度要快得多,并且消耗的 CPU 和内存要少得多,请参阅:secure.php.net/manual/en/migration70.phpsecure.php.net/manual/en/migration71.phpsecure.php.net/manual/en/migration72.php
  • 干得好,反应快。我可以说出那里发生的事情,并且与您的正常语言水平不符。 ;-)
【解决方案2】:

这是 PHP(和其他编程语言)没有直接在他们的书中直接说明的差距:您可以有两次相同的变量名(在您的情况下为 $error),但即使相同,这两个不要识别相同的变量(寻址相同的内存)。

一开始这可能看起来不太直接,但是当它涉及构建一个更大的程序时会变得更有意义,因为相当多的易于理解的变量名称都是有限的,因此使每个变量都可以在全局命名空间中通过其名称访问很快就搞砸了整个程序代码。

因此,如果您有兴趣,我会在此处看到有关如何处理此问题的多条路线(如果没有,这里是 some existing Q&A regarding the static keyword in a PHP function)。

第一个比较懒惰,在数据处理方面很可能是不安全的,所以整体编程代码需要非常精确才能安全使用:“不要重新实现数组,全局使用就行”。您可以使用全局变量来做到这一点。

初始化应该在应用程序的开头完成:

$GLOBALS['errors'] = [];

然后,您可以在需要时向该变量添加新条目:

$GLOBALS['errors'][] = $error;

如果您需要再次以列表的形式获取错误,只需将其读出:

var_dump($GLOBALS['errors']);

这实际上是全局变量名errors。全局变量很强大,但维护起来也很昂贵,因为任何代码都可以(有意或通过错误)重置所有错误,例如,甚至更苛刻,将数组转换为字符串,下次某些代码想要添加新条目时将失败.

那么,不使用全局变量的解决方案会是什么样子呢?通过对错误集合的更可控访问的成本(和好处),您可以创建一个表示该错误列表的对象,并将其传递到您想要添加错误的任何地方。

但在展示对象实例之前,我首先展示一个静态类的示例,因为它可能更接近您的心智模型和函数并且它是静态变量-

使用静态修饰符实现,您可以创建一个不可访问的全局变量(私有静态全局),该变量只能由向其添加消息的函数(以及同一类的其他静态函数)访问。

然后很容易添加另一个能够返回该变量内容的全局可访问函数:

final class Errors
{
    private static $errors = [];

    public static function add(string $error): void
    {
        self::$errors[] = $error;
    }

    public static function get(): array
    {
        return self::$errors;
    }
}

该类提供对否则无法访问的静态变量 Errors::$errors 的有限访问。

它确实会在加载此类定义的那一刻自动初始化(例如,通过include/require 或自动加载器),可以通过以下方式添加新错误:

Errors::add($error);

错误可以通过以下方式读出:

var_dump(Errors::get());

现在将其用作全局变量更加安全,但是仍然只有一个全局错误列表,并且代码的每一部分都可以通过Errors::... 类标识符(类的名称)访问它。

因此,一段时间后所有可用名称都被消耗掉的问题并没有解决。

为了防止类可以从静态变为非静态,因此从全局静态函数移动到对象实例。这很容易做到,基本上只需删除静态修饰符并从self::$ 切换到$this-&gt;。很容易我一次完成整个示例:

final class Errors
{
    private $errors = [];

    public function add(string $error): void
    {
        $this->errors[] = $error;
    }

    public function get(): array
    {
        return $this->errors;
    }
}

现在要让这个类正常工作,它需要做更多的工作,因为它的好处是 更好的控制。首先它需要初始化:

$errors = new Errors;

之后需要将错误集合传递到需要添加错误的每个地方:

$errors->add($error);

如果您愿意,可以读出目前收集到的所有错误:

var_dump($errors->get());

最后一个变体需要您管理(并因此考虑)代码的哪些部分需要访问哪些特定的错误集合(因为您可以创建多个)。因此,乍一看,这是更多的工作,但从长远来看,这会大大简化事情。您可以更改错误 集合(例如存储在文件中以及数组旁边),无需更改添加消息的所有位置。

您可以为不同的用途提供不同的错误收集对象,例如仅在测试场景或程序的子模块中。

所以这也提供了更多的灵活性(只需从最低限度开始)。

中间的静态类现在可能看起来是圣杯,但我想说这些只是平庸的,并且会很快消耗大量代码,因为它们不如全局变量强大但也会消耗随着您的应用程序变大,该名称不能轻易更改。

如果用途明确,全局变量可以是一个强大的工具,也可以是静态访问。但问题在于细节,而且在更加差异化的层面上,在面向对象编程的意义上使用对象实例通常非常有用。

  • 全局变量 - 内存对象

  • 对象变量 - 编程对象(通过类定义为您提供更多控制,以控制随时间的变化,代码和数据形成自己的单元)

【讨论】:

    【解决方案3】:

    您在函数范围内定义 $errors 变量,在该范围之外它将不存在。

    静态仅表示在这种情况下将创建一次,而不是在范围之外可用,global 关键字可能会对您有所帮助,但老实说,我会推荐另一种方法(全局是一种不好的做法)。

    您可以从方法中返回错误数组:

    function addErrors($err) {
      static $errors = [];
      $errors[] = $err;
      return $errors;
    }
    

    一个更好的方法可能是创建一个类:

    class ErrorHandler {
      private static $errors = [];
    
      public static function addError($error) {
        self::$errors[] = $error;
      } 
    
      public static function getErrors() {
        return self::$errors;
      }
    
    }
    

    然后将其用作:

     ErrorHandler::addError('error');
     print_r(ErrorHandler::getErrors());
    

    【讨论】:

      【解决方案4】:

      来自文档:

      静态变量只存在于局部函数范围内,但它确实存在 当程序执行离开这个范围时不会失去它的价值。

      要使变量在函数范围之外可用,您可以改用 global 关键字:

      function addErrors($errmessage){
         global $errors;
         $errors[] = $errmessage; 
      }
      

      参考

      【讨论】:

        猜你喜欢
        • 2021-09-03
        • 1970-01-01
        • 1970-01-01
        • 2017-07-09
        • 2011-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多