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?
我正在尝试保存每个唯一的类实例,但是当传递参数时需要知道如何执行此操作 构造函数: p>
class SingleInstance {
private static $ instances = [];
公共静态函数加载($ class,$ args = null){
if($ args){
$ args = implode(',',$ args); //数组到字符串(这是最好的方法吗?)
}
if(array_key_exists($ class,self :: $ instances)){
return self :: $ instances [$ class];
}
self :: $ instances [$ class] = new $ class($ args);
return self :: $ instances [$ class];
}
}
代码> pre>
上面的问题是如果我想保存同一个类的两个实例,第一个实例总是唯一一个保存... p>
\ n
class Words {
private $ word;
public function __construct($ word){
$ this-> word = $ word;
}
public function show(){
return $ this-> word;
}
}
$ a = SingleInstance :: load('Words',['Dog']);
echo $ a - >显示(); //“狗”
$ b = SingleInstance :: load('Words',['Cat']);
echo $ b-> show(); //“Dog”,因为最后一个实例的参数已保存
code> pre>
如何修改 SingleInstance code>类以便它可以保存 每个包含发送给构造函数的不同参数的实例? p>
div>
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;
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;
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;
Here's a way to make your code 'work' - for as far as we know til now.
// in class SingleInstance
//..
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)) {
// also check for the value, which is the only difference between the instances so far.
$x=self::$instances[$class];
if($x->show() == $args) {
return self::$instances[$class];
}
}
self::$instances[$class] = new $class($args);
return self::$instances[$class];
}
//..
Will result in DogCat
(with the rest of your original code).
But to me it's not quite clear what the final goal will be, so it's hard to tell if this would be the right way to go.