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 解决一个加好友限制问题 或者有好的方案
  • ¥15 关于#java#的问题,请各位专家解答!
  • ¥15 急matlab编程仿真二阶震荡系统
  • ¥20 TEC-9的数据通路实验
  • ¥15 ue5 .3之前好好的现在只要是激活关卡就会崩溃
  • ¥50 MATLAB实现圆柱体容器内球形颗粒堆积
  • ¥15 python如何将动态的多个子列表,拼接后进行集合的交集
  • ¥20 vitis-ai量化基于pytorch框架下的yolov5模型
  • ¥15 如何实现H5在QQ平台上的二次分享卡片效果?
  • ¥30 求解达问题(有红包)