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 fastreport怎么判断当前页数
  • ¥15 Kylin-Desktop-V10-GFB-Release-JICAI_02- 2207-Build14-ARM64.iso有没有这个版本的系统啊
  • ¥15 能不能通过蓝牙将传感器数据传送到手机上
  • ¥20 100元python和数据科学实验项目
  • ¥15 根据时间在调用出列表
  • ¥15 R 包chipseeker 安装失败
  • ¥15 Veeam Backup & Replication 9.5 还原问题
  • ¥15 vue-print-nb
  • ¥15 winfrom的datagridview下拉框变成了黑色,渲染不成功
  • ¥20 利用ntfy实现短信推送