Это не сразу возможно в PHP прямо сейчас. Вот несколько альтернатив в порядке простоты реализации.
Сначала , если вы знаете все возможные преобразования между связанными классами, вы можете легко создать метод, который принимает текущий объект, заполняет чистый экземпляр нового класса и возвращает его. Это идея, которую вы упомянули в своем первоначальном вопросе. Это самая простая и безопасная вещь, которую вы могли сделать.
Второй , если вы используете достаточно современную версию PHP, вы можете использовать Сериализуемый интерфейс для изящного трюка. Если вы реализуете этот интерфейс, __sleep
/ __wakeup
никогда не вызывается, и ни один из них не является конструктором. Это означает, что вы можете использовать эти методы для дешевого трюка. Вот несколько глупых демонстрационных кодов без интерфейса для демонстрации:
[mcg@mcg-workstation ~]$ php -a
Interactive shell
php > class Foo { public $a; public $b; }
php > class Bar extends Foo { public $c; }
php > class Baz extends Foo { public $c; }
php > $one = new Bar();
php > $one_s = serialize($one);
php > echo $one_s;
O:3:"Bar":3:{s:1:"c";N;s:1:"a";N;s:1:"b";N;}
php > $one_s = explode(':', $one_s, 4);
php > print_r($one_s);
Array
(
[0] => O
[1] => 3
[2] => "Bar"
[3] => 3:{s:1:"c";N;s:1:"a";N;s:1:"b";N;}
)
php > $two_s = $one_s;
php > $two_s[1] = strlen('Baz'); $two_s[2] = '"Baz"';
php > $two_s = join(':', $two_s);
php > echo $two_s;
O:3:"Baz":3:{s:1:"c";N;s:1:"a";N;s:1:"b";N;}
php > $two = unserialize($two_s);
php > echo get_class($two);
Baz
Если вы не следовали, этот код заменяет имя класса в сериализованных данных. Сделав это, я только что преобразовал Bar
в Baz
со всеми теми же свойствами. Это действительно работает, только если свойства идентичны. Я не уверен, что будет делать PHP, если свойства не совпадают, и если вы реализуете Serializable, ваши методы сериализации и десериализации должны будут обрабатывать преобразование.
Это также огромный взлом, который может заставить будущих разработчиков вашего кода захотеть отследить вас и причинить вам вред. Также возможно незначительное снижение производительности. Если вы в конечном итоге используете его, обязательно сравните тест. И нанять телохранителей. Или, по крайней мере, убедитесь, что будущие сопровождающие не будут психопатами-убийцами, которые смогут найти ваш адрес.
Третий , возвращаясь к построению на основе классов вместо построения на основе объектов: если вы можете ждать PHP 5.4 (или чего-то еще, чем в конечном итоге будет текущий ствол), вы сможете разместить анонимные функции в свойствах и вызывать их, как если бы они были методами. Хотя в более ранних версиях можно размещать анонимные функции в свойствах, по крайней мере, начиная с PHP 5.3, эти функции не могут ссылаться на $this
и поэтому совершенно бесполезны как часть объекта. Это ограничение также препятствует использованию магического метода __call
для достижения того же самого результата прямо сейчас.
Четвёртый , и это полный не ответ, рассмотрите Ruby или Perl, если вы хотите такого рода изгибающую гимнастику. Я думаю, что Python может делать подобные вещи, но я не работал в этом и не уверен. PHP не является гибким языком, когда дело доходит до ОО, и люди из внутреннего списка не заинтересованы в том, чтобы привести ОО к более интересным стандартам других языков.
Что касается вашей связанной проблемы, похоже, вы действительно хотите получить черты уровня экземпляра. PHP 5.4 также будет иметь черты, но на уровне класса, а не на уровне экземпляра. См. # 4 для моего комментария об этом.