Как инициализировать экземпляр класса PHP с помощью другого экземпляра объекта? - PullRequest
5 голосов
/ 30 сентября 2010

Что было бы хорошим способом (вместе с любыми плюсами и минусами) инициализации экземпляра класса PHP другим объектом того же класса (в идеале в PHP 4.x) ?

Здесь, в initialize(), это, по сути, то, что я хотел бы сделать (пример чрезвычайно упрощен из моего сценария использования, см. Ниже):

$product = new Product('Widget');
$product2 = new Product('Widget #2');
$product->initialize($product2);
echo $product->name;  // echos "Widget #2"

class Product {
 var $name;
 function __constructor($name) {
   $this->name = $name;
 }
 function initialize($product) {
   // I know this cannot be done this way in PHP. 
   // What are the alternatives and their pros & cons?
   $this = $product;  
 }
}

Я знаю, что это не может быть "хорошей практикой программирования";с более чем 20-летним опытом программирования на других языках, я знаю немного о том, что хорошо, а что нет.Надеюсь, мы не будем зацикливаться на том, имеет ли это смысл или нет.У меня есть сценарий использования, работающий с некоторым кодом с открытым исходным кодом, который я не могу изменить, поэтому, пожалуйста, просто позаботьтесь о моей необходимости.Я на самом деле пытаюсь создать оболочку ООП вокруг какого-то действительно уродливого кода массива, закопанного глубоко в ядре WordPress.

Я пытаюсь написать его, чтобы в будущих версиях они могли двигатьсяот уродливого кода на основе массива, потому что каждый будет использовать новый API, который в противном случае полностью инкапсулирует эти неприятные массивы.Но для того, чтобы это работало элегантно, мне нужно иметь возможность выполнить вышеизложенное (в PHP 4.x), и я не хочу писать код, который просто копирует свойства.

Заранее спасибо заваша помощь.

ОБНОВЛЕНИЕ

Многие из вас предлагают clone, но если я не пойму, что это не решает вопрос.clone делает копию;это не суть вопроса. Вместо этого я пытаюсь заставить построенный объект "стать" переданным объектом. На данный момент я предполагаю, что нет способа сделать это на основефакт, что 0 из 5 ответов предложили что-нибудь, но я подожду немного дольше, прежде чем выбрать лучший, в случае, если мои вопросы просто неясны.

Ответы [ 6 ]

5 голосов
/ 30 сентября 2010

В PHP 5 клонирование объектов может быть более актуальным:

http://php.net/manual/en/language.oop5.cloning.php

Вы можете определить специальный метод __clone.

В PHP 4 и 5 вы можете копировать свойства с помощью:

function copy($obj)
{
  foreach (get_object_vars($obj) as $key => $val)
  {
     $this->$key = $val;
  }
}

Однако вы написали «Я не хочу писать код, который просто копирует свойства», и я не совсем уверен, что вы подразумеваете под этим.

2 голосов
/ 30 сентября 2010

Предпочтительный способ сделать это - использовать ключевое слово clone и реализовать соответствующий метод __clone(), если это необходимо, как упоминалось другими авторами.Еще один хитрый способ сделать это (con: slow, pros: может быть сохранен, отправлен по сети и работает идентично в php4 / 5) - это сериализовать объект и затем десериализовать для создания его новых копий с идентичными значениями переменных.

Пример:

$productCopy = unserialize(serialize($product));

РЕДАКТИРОВАТЬ: Извините, неправильно понял, что вы просили.Вам нужно будет инициализировать переменные объекта, который создается с помощью переданных в объекте переменных внутри конструктора.Вы не можете вернуть ссылку на другой объект из конструктора.

Пример:

public function __construct($name, $object = null) { 
    if($object) { 
        foreach(get_object_vars($object) as $k => $v) {
            $this->$k = $v;
        } 
    } else {
        $this->name = $name;
    }
} 
1 голос
/ 29 декабря 2011

На данный момент это лучший способ сделать это:

http://www.blrf.net/howto/51_PHP__How_to_control_object_instances_in_PHP_.html

Не используйте «new», вместо этого используйте статическую функцию, которая возвращает нужный вам экземпляр.

Я сделал следующее:

class MyClass {

    private static $_instances;

    public static function get($id) {
        if (!self::$_instances) self::$_instances = Array();
        $class = get_called_class();

        if (!array_key_exists($class, self::$_instances)) self::$_instances[$class] = Array();

        if (!is_numeric($id) || $id == '') throw new Exception('Cannot instantiate a non-numeric ID.');

        if (array_key_exists($id, self::$_instances[$class])) return self::$_instances[$class][$id];
        else {
            self::$_instances[$class][$id] = new static($id);
            return self::$_instances[$class][$id];
        }
    }

    function __construct($id=false) {
        // new instance code...
        // I use $id=false to create new a db table row not load an old one
    }

}

Использование:

// New instance
$a = new MyClass();
$a = new MyClass;

// MyClass with $id = 1
$b = MyClass::get(1);
$c = MyClass::get(1);
$d = new MyClass(1);
$b and $c point to the same object, while $d is a new one.

Предостережения:

  • Сборка мусора больше не будетприменить, поскольку ваши экземпляры хранятся в статическом массиве

  • Вам придется изменить свой код, чтобы использовать MyClass :: get

Примечания вмой код:

  • Новые экземпляры вызываются с помощью "new static" вместо "new self" для использования поздних статических привязок.

  • Вы можетеустановите ваш конструктор как приватный.Это сломает весь ваш старый код, если вы используете «новый», но гарантируете, что вы не получите двойные экземпляры или больше.Вам нужно будет немного изменить аргументы и код функции get, чтобы $ id = false или $ id = -1 или что-то еще.

1 голос
/ 30 сентября 2010
class Product {
    var $name;
    function __construct($value) {
        if (is_a($value, 'Product')) {
            $this->name = $value->name;
        } else {
            $this->name = $value;
        }
    }
}

Аналогично, вы можете использовать instanceof вместо is_a, если хотите (в зависимости от вашей версии PHP).

Теперь вы можете передать экземпляр Product ИЛИ имя в конструкцию.

$product = new Product('Something');
$clone = new Product($product);
0 голосов
/ 30 сентября 2010

Добавление другого ответа из-за радикального отличия.

$product = new Product('Widget');
$product2 = new Product('Widget #2');
$product =& $product2;
echo $product->name;  // echos "Widget #2"

Это должно сработать.

0 голосов
/ 30 сентября 2010

возможно

$product = new Product('Widget');
$product2 = new Product(null, $product);
echo $product2->name;  // echos "Widget #2"

class Product {
 var $name;
 function __constructor($name, $product = null) {
   $this->name = !empty($name) ? $name : $product->name;
 }
}
...