doushenmao9036 2018-03-01 00:02
浏览 108
已采纳

PHP:将参数传递给构造函数时保存类实例

I am attempting to save each unique class instance, but need to know how to do so when there are arguments passed to the constructor:

class SingleInstance {

  private static $instances = [];

  public static function load($class, $args=null) {

    if ($args) {
      $args = implode(', ', $args); // Array to string (is this the best way?)      
    }

    if (array_key_exists($class, self::$instances)) {
      return self::$instances[$class];
    }

    self::$instances[$class] = new $class($args);
    return self::$instances[$class];

  }

}

The problem with the above is if I want to save two instances of the same class, the first instance is always the only one saved...

class Words {

  private $word;

  public function __construct($word) {
    $this->word = $word;
  }

  public function show() {
    return $this->word;
  }

}

$a = SingleInstance::load('Words', ['Dog']);
echo $a->show(); // "Dog"

$b = SingleInstance::load('Words', ['Cat']);
echo $b->show(); // "Dog" because the arguments from the last instance was saved

How can I modify the SingleInstance class so that it will save each instance which contains different arguments sent to the constructor?

  • 写回答

2条回答 默认 最新

  • duanqian6982 2018-03-01 01:35
    关注

    I'm with @Jeff, it's a bit unclear what you are trying to do. You can replace array_key_exists() with in_array(), and check if the new instance is contained in the $instances array (obviously not the same, but one with the same properties, which is why we don't use a strict comparison in in_array()).

    Then, you can save all the instances with different parameters in your cache, and as soon as you find one in the array, just return it.

    <?php
    class SingleInstance
    {
        private static $instances = [];
    
        public static function load($class, $args = null)
        {
            if ($args) {
                $args = implode(', ', $args);
            }
    
            $c = new $class($args);
            if (in_array($c, self::$instances)) {
                echo "Hit!";
                return self::$instances[$class];
            }
    
            self::$instances[$class] = $c;
            return self::$instances[$class];
        }
    }
    
    class Words
    {
        private $word;
    
        public function __construct($word) {
            $this->word = $word;
        }
    
        public function show() {
            return $this->word;
        }
    
    }
    $a = SingleInstance::load('Words', ['Dog']);
    echo $a->show().PHP_EOL;
    
    $b = SingleInstance::load('Words', ['Cat']);
    echo $b->show().PHP_EOL;
    
    $c = SingleInstance::load('Words', ['Cat']);
    echo $c->show().PHP_EOL;
    

    Demo

    The downside to this is that you're trying to do some kind of cache, it's worthless since you're instantiating the class anyway in order to test if you already have it.

    If this is some kind of cache, then you can give it a try computing a checksum of the class' name and arguments and using that as a key (in this case you can keep your initial array_key_exists() call):

    <?php
    class SingleInstance
    {
        private static $instances = [];
    
        public static function load($class, $args = null)
        {
            if ($args) {
                $args = implode(', ', $args);
            }
    
            $checksum = md5($class.$args);
            if (array_key_exists($checksum, self::$instances)) {
                echo "Hit!";
                return self::$instances[$checksum];
            }
    
            self::$instances[$checksum] = new $class($args);
            return self::$instances[$checksum];
        }
    }
    
    class Words
    {
        private $word;
    
        public function __construct($word) {
            $this->word = $word;
        }
    
        public function show() {
            return $this->word;
        }
    
    }
    $a = SingleInstance::load('Words', ['Dog']);
    echo $a->show().PHP_EOL;
    
    $b = SingleInstance::load('Words', ['Cat']);
    echo $b->show().PHP_EOL;
    
    $c = SingleInstance::load('Words', ['Cat']);
    echo $c->show().PHP_EOL;
    

    Demo

    And about your first question in the comments, this code works with just one argument, but it will break with more. To fix this, use argument unpacking:

    <?php
    class SingleInstance
    {
        private static $instances = [];
    
        public static function load($class, $args = null)
        {
            $checksum = md5($class.implode(', ', $args));
            if (array_key_exists($checksum, self::$instances)) {
                echo "Hit!";
                return self::$instances[$checksum];
            }
    
            self::$instances[$checksum] = new $class(... $args); // argument unpacking
            return self::$instances[$checksum];
        }
    }
    
    class Words
    {
        private $word;
        private $word2;
    
        public function __construct($word, $word2) {
            $this->word = $word;
            $this->word2 = $word2;
        }
    
        public function show() {
            return $this->word." ".$this->word2;
        }
    
    }
    $a = SingleInstance::load('Words', ['Dog', 'Word1']);
    echo $a->show().PHP_EOL;
    
    $b = SingleInstance::load('Words', ['Cat', 'Word2']);
    echo $b->show().PHP_EOL;
    
    $c = SingleInstance::load('Words', ['Cat', 'Word2']);
    echo $c->show().PHP_EOL;
    

    Demo

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

报告相同问题?

悬赏问题

  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助