PHP函数中的静态数组不起作用

时间:2018-04-29 07:31:05

标签: php static

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

此函数只接收一条消息并将其添加到errors []数组中,然后能够在函数外部使用此错误列表[]。

我收到错误消息: "注意:未定义的变量:第10行和第34行中的错误;

第10行有代码" print_r($ errors);"

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

感谢您的投入!

4 个答案:

答案 0 :(得分:3)

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

静态只意味着在这种情况下它会被创建一次,而不是它在范围之外可用,global关键字可能会帮助你,但说实话,我建议采用另一种方法(全局是不好的做法)。

您可以从方法返回errors数组:

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());

答案 1 :(得分:3)

这是一个差距,PHP(和其他编程语言)不会直接在他们的书中预先说明:你可以有两倍相同的变量名称(在你的情况下$error),但即使是同样,两者不识别相同的变量(寻址相同的内存)。

这一开始可能看起来很简单,但是当它构建一个更大的程序时,它变得更有意义,因为所有可以理解的变量名称都是有限的,所以在全局范围内可以通过它来获取每个变量的名称。名称空间会很快弄乱整个程序代码。

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

第一个是非常懒惰的,并且在数据处理方面很可能不安全,因此整体编程代码需要非常精确才能安全使用它:"不要重新实现数组,只需在全球使用它"。你可以用全局变量来做到这一点。

初始化应在应用程序开始时完成:

$GLOBALS['errors'] = [];

然后,只要您认为需要,就可以在该变量中添加新条目:

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

如果您需要再次将错误作为列表获取,请阅读:

var_dump($GLOBALS['errors']);

这实际上是全局变量名errors。全局变量功能强大但维护成本也很高,因为任何代码都可以 - 通过预期或错误 - 重置所有错误,例如甚至更严厉,将数组转换为字符串,下次某些代码想要添加新条目将失败

那么如何不使用全局变量的解决方案呢?通过对错误集合进行更多受控访问的成本(并且有益处),您可以创建一个表示错误列表的对象,并将其传递到您想要添加错误的位置。

但在展示对象实例之前,我首先展示一个静态类的例子,因为它可能更接近你的心理模型w / the function及它的静态变量 -

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

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

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->。这很容易我立即做完整个例子:

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());

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

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

因此,这也提供了更大的灵活性(只需从最小开始)。

中间的静态类似乎是现在的圣杯,但是我说这些只是平庸,并且会很快耗尽你的代码,因为它们没有全局变量那么强大但是还会消耗随着应用程序变大而无法轻易更改的名称。

如果使用清楚,全局变量可以是一个强大的工具,也可以是静态访问。但是魔鬼在细节中处于更加不同的层面,因此在面向对象编程的意义上使用对象实例通常非常有用。

  • 全局变量 - 记忆对象

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

答案 2 :(得分:2)

$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&gt; =:

<?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());

答案 3 :(得分:1)

来自文档:

  

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

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

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

参考