dongzang5815 2014-04-24 12:06
浏览 36
已采纳

php类设计:只有一个实例始终可访问

in my php application, I'm aggregating some rss feeds. I want this to be done every 24h and I don't want to store it in database.

I have built a singleton class that creates my rss informations ($ActuList) :

class ActualitesManager{

/**
* @var Singleton
* @access private
* @static
*/
private static $_instance = null;

public $ActuList = null;

private function __construct()
{
    error_log("construct");
    /* My stuff to create $ActuList */

}

public static function getInstance()
{

    error_log("instance before : ". json_encode(self::$_instance) );
    //if(is_null(self::$_instance)){
    //if(!isset(self::$_instance)){
    if (null === self::$_instance)
{
        $object = __CLASS__;
        self::$_instance = new $object;
    }else
{
        error_log("skip constructor");
    }
    error_log("instance after : ". json_encode(self::$_instance) );
    return self::$_instance;
}    

}

but each call to the getInstance() calls the constructor as it should normally be done only once and then give the already instanciated $_instance

My debug always gives :

instance before : null
instance after : {"ActuList":null}

and never displays the "skip constructor".

What am I missing ?

and in a general way : is this the correct way to do ? As parsing rss feeds is time consuming I don't want this task to be done for each visitor : how to keep results in an always instanciated php class ?

Thanks for your ideas !

  • 写回答

2条回答 默认 最新

  • duanbi3151 2014-04-24 13:23
    关注

    I don't want this task to be done for each visitor : how to keep results in an always instanciated php class

    I focused on that part of the question, which makes me think that you rather missconcept the Singleton pattern, objects and requests.

    Let me change your sample as another demonstration which maybe you will understand better

    <?php
    
    class Singleton {
        public $x = 1;
    
        private static $_inst = null;
    
        private function __construct() { }
    
        /**
         * @return Singleton
         */
        public static function getInstace() {
            if (self::$_inst == null) {
                self::$_inst = new self();
            }
            return self::$_inst;
        }
    }
    
    if (isset($_POST['y'])) {
        Singleton::getInstace()->x++;
        echo Singleton::getInstace()->x;
    }
    ?>
    
    <form action="" method="post">
        <input type="submit" name="y"/>
    </form>
    

    We have a Singleton class which contains public property $x accessible via its instance. Since constructor is private, you can access instance only from getInstance() method. Singleton::getInstace()->x will access the property $x.

    In this code, if the button is clicked, we expect the $x property to increment by one.

    When we first launch the script, the property has value of 1. After we press the button, it has value of 1 + 1 = 2. And now, you expect, the value of 2 somehow to be written in the memory, so if the button is clicked for third time, it should show 3. But, it unfortunately is not true, and no matter how many times you do click the button, you will always recieve a value of 2, since after requesting the page for N-th time, it reinstantiates the class and it loses all of its changes.

    There is no way to keep that persistence between all your clients only in the memory, because it's flushed right after it is used.

    My suggestion is to keep changes into a database.

    You can also do an object serialization, so you can save your changes into the database;

    E.g.:

    serialize(Singleton::getInstance());
    

    outputs:

    O:9:"Singleton":1:{s:1:"x";i:1;}
    

    You can store this somewhere i.e. in db col serialized

    afterwards extract it and assign it to variable:

    $singleton = unserialize($row['serialized']);
    

    Perform a change:

    $singleton->x++;
    

    See the serialized changes again:

    O:9:"Singleton":1:{s:1:"x";i:2;}
    

    Save them back.

    Assign again

    $singleton = unserialize($row['serialized']);
    $singleton->x++;
    echo $singleton->x;
    

    Outputs: 3

    This might not be the most efficient way, but you cannot rely on PHP objects to save in memory like database. That's why databases are present, and all the information for users, etc. is not stored into objects kept in the memory.

    If there are a lot of credentials to save, the best design decision is to save each field into the DB instead of a serialized object, so you can set to the new instance the value from the database. That's what, in practice, the ORM's are for. Bind resultset to object.

    Think twice which approach can fit your needs, if reinstantiating an object / pulling from the database for each user is costly, you should think about a caching approach, if no changes - no db pull, take from the cache.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮