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 我的b站在没有碰到屏幕的情况下偶尔会自动跳出进度条,就像在屏幕上点了一下一样,但我并没有点。而且视频进度并没有变。这可能是什么原因造成的?
  • ¥30 STK matlab python仿真
  • ¥15 关于IMageEnView 图标定位问题
  • ¥20 求解答(matlab)
  • ¥30 ffmpeg库使用过程中遇到的问题
  • ¥15 pyqt5 中python如何通过Qtwebchannel主动发消息给web前端
  • ¥15 关于HTML中title获取xml内容的问题
  • ¥15 fanuc机器人PRIO083数字信号未复原错误,如何解决?
  • ¥20 如何为现有电路板增加远程控制功能
  • ¥15 UE5打包失败,求解决