Можно ли конвертировать между классами с общим родителем? - PullRequest
0 голосов
/ 21 октября 2009

Если у меня есть два класса, каждый из которых расширяет общего родителя, можно ли конвертировать между ними?

class Foo
{

    public $bar;


}

class FooDatabase extends Foo
{

    public function load() {}

    public function save() {}

}

class FooFlatfile extends Foo
{

    public function load() {}

    public function save() {}

}

$foo = new FooDatabase;
$foo->bar = 'elf';

Используя этот код в качестве примера, я хочу преобразовать $foo из экземпляра FooDatabase в FooFlatfile, сохраняя при этом значение свойства bar.

Редактировать: Я понимаю, что на самом деле делать это не такая хорошая идея на практике. Скорее я столкнулся с ситуацией, в которой это было потенциальное решение, и мне стало любопытно, как этого можно достичь.

Ответы [ 3 ]

2 голосов
/ 21 октября 2009

Это возможно, хотя и не рекомендуется. Взгляните на Темный угол PHP: приведение классов . В основном:

  1. Сериализация класса;
  2. Изменить имя класса в сериализованной форме; то
  3. Десериализовать его.

Да, это взлом.

Большой вопрос: почему вы хотите это сделать? Если вам нужно изменить класс, это очень сильный показатель того, что ваша объектная модель плохая. Это напоминает мне старые примеры вводного ОО, которые они давали:

  • Персональный класс;
  • Продавец расширяет лицо;
  • Менеджер расширяет лицо.

, который является ужасным примером по той же причине: что, если кто-то перейдет из продавца в менеджера? Сравните это с композиционным подходом, в котором Person имеет-1028 * Job (где Manager и Sales являются экземплярами или подклассами Job). Гораздо более разумный подход.

Наконец, я добавлю, что если какой-то код, который вы не можете изменить, заставляет вас делать это, то лучше использовать какой-нибудь адаптер или фасад:

class A { ... }
class B {
  public function asA() {
    $ret = new A;
    // configure;
    return $ret;
  }
  ...
}

Опять же, это намного более звучит, чем любой процесс автоматического изменения класса копирования свойств.

1 голос
/ 30 июля 2011

Вы можете сделать что-то вроде этого, иметь некоторые ограничения (ограничения на типы конструкторов и не можете копировать приватные переменные), но это можно заставить работать.

class Foo {
  public $bar;

  protected function convertTo($classname) {
    $rc_other_class = new ReflectionClass($classname);
    if ($rc_other_class->isSubclassOf(get_class())) {
      // there's a limitation here in that the constructor can't take params
      $other_class = new $classname();
      $rc_this_class = new ReflectionClass(get_class());
      $properties = $rc_this_class->getProperties();
      foreach ($properties as $property) {
        if (!$property->isStatic() &&
            $property->getDeclaringClass()->getName() == get_class()) {
          $property = $property->getName();
          if (property_exists($this, $property)) {
            // this will throw if you try to copy a private var, add a filter to
            // getProperties to prevent this but you probably want the error
            $other_class->$property = $this->$property;
          }
        }
      }
    } else {
      return false;
    }
  }
}
1 голос
/ 21 октября 2009

Можете ли вы сделать то, что вам нужно, создав новый и скопировав значения?

$foo2 = new FooFlatFile;
$foo2 = foo->bar;

Если не получается, что вам нужно, пожалуйста, дайте нам более подробную информацию.

Ответ на комментарий:

Если вы планируете делать это часто, было бы легко создать функцию-член, которая будет возвращать все члены в каком-либо массиве или структуре. Однако в этот момент вам действительно нужно спросить себя: «Почему я это делаю?» Другой респондент говорит, что если вы регулярно хотите это делать, вы очень плохо спланировали свои занятия.

Если у вас есть два класса, между которыми вы хотите переключиться, удалите то, что их разделяет, и создайте один класс. Либо они в основном одинаковы, и в этом случае вы могли бы сойти с рук, переключаясь между ними, но вам гораздо лучше обслужить, сделав всего один урок.

Или они принципиально отличаются друг от друга, и в этом случае вам все еще нужны два класса. Если у вас есть база данных, и вы пытаетесь превратить ее в плоский файл, вам нужна функция экспорта, которая переводит базу данных в простые данные. Динамически изменяющиеся классы были бы похожи на использование Блокнота для открытия файла Oracle: он не давал бы данные осмысленным и удобным способом. Чтобы переходить между ними, вы пишете функции экспорта и импорта, которые используют ту же структуру данных, что и другие. Вы создаете новый, экспортируете из старого, импортируете в новый и удаляете старый.

Я, честно говоря, не уверен, что еще сказать, потому что я не могу представить сценарий, в котором было бы целесообразно сделать это. Если бы вы могли дать более подробную информацию о том, что вы пытаетесь решить, я мог бы предложить лучший совет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...