【问题标题】:Function calling itself infinitely?函数无限调用自己?
【发布时间】:2014-02-20 00:03:13
【问题描述】:

我在做一个 PHP 类的小实验,遇到了这个奇怪的问题。

该类旨在为其 $instance 属性分配一个自身的实例以防 $instance 为 null,但这种机制是应该防止无限的自我繁殖似乎失败了,这就是发生的事情:

致命错误:已达到最大函数嵌套级别“100”,正在中止!

<?php
class SeemsLikeInfinity {

public $instance;

public function __construct() {

    if ( $this->instance == null ) {

        $this->instance = new self;

    }
}

}

$looping = new SeemsLikeInfinity();

?>

为什么会这样? __construct 只是创建了一个空的类的新实例,因此具有空的 $instance,因此再次创建实例,使循环无限?

非常感谢

【问题讨论】:

    标签: php loops constructor infinity


    【解决方案1】:

    这是因为参数 $instance 始终为空。每次在类中创建新对象时。如果你想实现单例,你应该将 __construct 更改为私有并使用一种静态方法来创建一个对象

     class SeemsLikeInfinity {
    
       private static $instance;
    
       private function __construct() {
           // some action;
       }
       public static function generate_singleton(){
         if ( self::$instance == null ) {
             self::$instance = new self;
         }
         return self::$instance
       }
    }
    
    $singleton = SeemsLikeInfinity::generate_singleton();
    // here you have singleton and you cant create more tha one object
    

    【讨论】:

    • 我可能错了 - 但这会导致Fatal error: Using $this when not in object context
    【解决方案2】:

    当您使用“new”关键字创建对象时,它会调用构造函数。如果在构造函数中使用new self,它将再次调用构造函数。导致无限循环。

    当您使用new 时会自动创建一个新实例,因此您不必存储$this-&gt;instance 之类的内容。变量$this 你的实例。

    要记住的重要一点是类的每个实例都有自己的变量$instance。所以它在整个过程中始终为 null。

    现在,如果你想创建一个单例,你实际上必须将构造函数设为私有:

    private function __construct() {}
    

    那么我们需要instance 是一个静态变量:

    static private $instance;
    

    没有人可以使用 new 关键字创建新对象。那么接下来我们需要提供一个静态函数来创建实例:

    static function newInstance() {
        if ( self::instance == null ) {
            self::instance = new self;
        }
        return self::instance;
    }
    

    现在您可以使用以下方法获得新实例:

    $x = SeemsLikeInfinity::newInstance();
    

    现在只有一个 SeemsLikeInfinity 对象,您可以随时使用SeemsLikeInfinity::newInstance() 访问它

    【讨论】:

    • 谢谢,这是尝试实现单例模式,但我可能弄错了。我知道 $this 代表当前对象的实例,我试图创建一个可以使用 $object->instance->doSomething() 访问的对象,而该实例包含 $object 的实例。
    • 这也会导致Fatal error: Using $this when not in object context我相信...
    • @CD001 谢谢,需要将变量设为静态。
    【解决方案3】:

    您必须使用静态变量而不是 $this 的原因是 $this 仅与当前对象相关 - 每次创建新的 SeemsLikeInfinity 对象时,您都会为此创建一个新的 $this对象 - 因此,当您实例化类时,$this-&gt;instance 始终是 null

    那么,你的构造函数中发生了什么:

    if ( $this->instance == null ) {
      $this->instance = new self;
    }
    

    ... 是一个新的$this-&gt;instance(没有赋值)是在构造对象时创建的,所以一个新的对象是用一个新的$this-&gt;instance 构造的,同样没有值,所以一个新的对象是用一个新的$this-&gt;instance,再次没有值......等等,永远。

    然而,静态变量是相对于类本身的...您可以根据需要多次实例化该类,并且创建的每个对象都将从该类继承静态变量的最后设置值。

    您要做的是创建一个 Singleton,因此您永远不会直接调用构造函数,而是通过静态 getInstance() 方法实例化和访问该类:

    // I've made this a "final" class - you can't really
    // extend Singletons without getting into a mess
    final class SeemsLikeInfinity {
    
      // this needs to be a static variable as it'll
      // be checked from the static self::getInstance() method
      // it should also be private as you'll never call it from
      // outside the class
      private static $instance;
    
      // the constructor function should also be private
      // as it'll ONLY ever be called from the 
      // self::getInstance() method
      private function __construct() {
        // ... do stuff here to instantiate your class
      }
    
      // Singletons can't be cloned
      public function __clone() {
        throw new Exception("ERROR : you can't clone Singletons", E_USER_ERROR);
      }
    
      // this is the main getInstance() method called
      // to actually instantiate or call the class
      public static function getInstance() {
        if(!self::$instance) { self::$instance = new self(); }
        return self::$instance;
      }
    }
    
    // now, to instantiate or access your class you'd use getInstance()
    // you'll no longer have permanently reiterating classes and you
    // should be golden
    $looping = SeemsLikeInfinity::getInstance();
    

    顺便说一句,我发现单例的最佳用途是构建会话管理包装器,因为会话本质上只有一个实例。

    【讨论】:

      猜你喜欢
      • 2022-11-28
      • 1970-01-01
      • 2014-11-22
      • 2022-06-16
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多