PHP Singleton: достигнут максимальный уровень вложенности функции ‘100’, прерывание

Я пишу собственное PHP-приложение с нуля и для некоторых классов использую singleton шаблон, потому что мне нужна информация, которая будет рассчитана один раз, и я просто использую их. Сегодня я написал большую часть своего Приложения, и когда я тестировал все это, оно выдает мне следующую ошибку: Достигнут максимальный уровень вложенности функции ‘100’, прерывание. Я сделал несколько тестов и обнаружил, что ошибка генерируется чем-то вроде этого:

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

Bar.php

class Bar
{
public function doSomething()
{
F()->showSomeInformation();
}
}

На мой взгляд, это действительно потому, что F() был вызван ранее, и он должен иметь в статической переменной экземпляр Foo, и я считаю, что он должен как-то работать, но это не так.

Я чувствую себя потерянным сейчас. Как заставить его работать или хотя бы как что-то изменить, чтобы иметь похожее поведение?

0

Решение

Хорошо, я уже упоминал об этом в комментариях, но здесь вы идете.

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

Если вы используете шаблон синглтона, убедитесь, что сам класс отслеживает, был ли он инициализирован или нет. Разрешение обработки внешнего источника может вызвать много проблем (как вы только что испытали).

1

Другие решения

Бесконечная рекурсия происходит в конструкторе 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, который вызовет F () перед возвратом объекта Foo, но F () вызовет конструктор для еще одного Foo, который будет делать то же самое, навсегда, поэтому никаких новых Foo будет когда-либо возвращаться из F (), поэтому у нас заканчивается стек.

Вот пример нормального одноэлементного паттерна в PHP.
http://www.phptherightway.com/pages/Design-Patterns.html

0

Мне не нравится паттерн Синглтона, и я думаю, если у вас есть небольшой опыт и вы начнете с юнит-тестирования, вы его тоже ненавидите. Но шаблон работает не так, как вы пробовали.

class MySingletonClass
{
private static $instance;

//make 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();
0
По вопросам рекламы [email protected]