我从头开始编写一个自定义的PHP应用程序,对于某些类,我使用单例模式,因为我需要计算一次信息,而我只是使用它们。
今天我写了我的应用程序的很大一部分,当我测试它时,它给我抛出了以下错误:
达到最大函数嵌套级别"100",正在中止。
我做了一些测试,发现错误是由这样的东西产生的:
文件索引.php
class Foo
{
public function __construct()
{
if(!class_exists('Bar', false))
{
require 'Bar.php';
}
$bar = new Bar;
$bar->doSomething();
}
public function showSomeInformation()
{
// information
}
}
function F()
{
static $instance = null;
if(is_null($instance))
{
$instance = new Foo;
}
return $instance;
}
F();
文件栏.php
class Bar
{
public function doSomething()
{
F()->showSomeInformation();
}
}
在我看来,它是有效的,因为之前调用过F()
并且它应该在静态变量中具有 Foo 的实例,我相信它应该以某种方式工作,但它没有。
我现在感到迷茫。我怎样才能让它工作,或者至少我怎样才能改变一些东西来具有类似的行为?
$instance
值始终保持null
。为什么?好吧,在将实例分配给$instance
之前,看看会发生什么。
在$instance
具有任何不同的值之前,您再次调用$bar->doSomething();
。
这意味着您再次运行F()
,但$instance
仍然null
。现在你再次实例化Foo
,但猜猜什么$instance
仍然是空的。
试试这个:
<?php class Foo
{
static $instance = null;
public function __construct()
{
if(!class_exists('Bar', false))
{
require 'Bar.php';
}
self::$instance = $this;
$bar = new Bar;
$bar->doSomething(self::$instance);
}
public function showSomeInformation()
{
// information
}
}
class Bar
{
public function doSomething($instance)
{
F($instance)->showSomeInformation();
}
}
function F($instance = null)
{
if(is_null($instance))
{
$instance = new Foo;
}
return $instance;
}
F();
如果使用单例模式,请确保类本身跟踪它是否已初始化。 让外部源处理此问题可能会导致很多问题(正如您刚刚遇到的那样)。
无限递归发生在 foo 的构造函数中:
function F()
{
static $instance = null;
if(is_null($instance))
{
$instance = new Foo;
echo("Never reached'n");
if( is_null($instance) )
{
echo("Still null!'n");
}
}
return $instance;
}
第一个 F(); 调用不会创建 Foo。它将调用 Foo 的构造函数,这将在返回 Foo 对象之前调用 F(),但 F() 在另一个 Foo 上调用构造函数,它将永远做同样的事情,因此没有新的 Foo 会从 F() 返回。所以我们用完了堆栈。
下面是 PHP 中一个理智的单例模式示例:设计模式
我不喜欢单例模式,我想,如果你有一点经验并从单元测试开始,你也会讨厌它。但是该模式并不像您尝试的那样有效。
class MySingletonClass
{
private static $instance;
// Make the constructor protected, to prevent direct instantiation
protected function __construct() {}
/**
* @return MySingletonClass
*/
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self(); // new static() would we valid too, relevant for extending (late state binding)
}
return self::$instance;
}
public function getSomething()
{
if (!$this->calculated) {
$this->calculated = $this->calculateSomething();
}
return $this->calculated;
}
}
echo MySingletonClass::getInstance()->getSomething();