現在、これはPHPではすぐには不可能です。実装が容易な順に、いくつかの選択肢を示します。
まず、関連するクラス間で可能なすべての変換がわかっている場合は、現在のオブジェクトを取得し、新しいクラスのクリーンなインスタンスにデータを入力して返すメソッドを簡単に作成できます。これは、元の質問で言及したアイデアです。それはあなたができる最も簡単で安全なことです。
次に、十分に最新バージョンのPHPを使用している場合は、Serializableインターフェースを使用して巧妙なトリックを行うことができます。そのインターフェースを実装する場合、__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
従わなかった場合、このコードはシリアル化されたデータのクラス名を置き換えます。これを行うことで、すべて同じプロパティを持つaをに変換しBar
ました。Baz
これは、プロパティが同一である場合にのみ実際に機能します。プロパティが一致しない場合にPHPが何をするかはわかりません。また、Serializableを実装する場合は、serializeメソッドとunserializeメソッドで変換を処理する必要があります。
これはまた、あなたのコードの将来のメンテナがあなたを追跡してあなたを傷つけたいと思うかもしれない途方もないハックです。おそらくマイナーなパフォーマンスのペナルティもあります。最終的に使用する場合は、必ずベンチマークを行ってください。そしてボディーガードを雇う。または、少なくとも将来のメンテナがあなたの住所を見つけることができる殺人的な精神病質者にならないようにしてください。
第3に、オブジェクトベースの構築ではなくクラスベースの構築に戻ります。PHP5.4(または現在のトランクが最終的になるもの)を待つことができれば、無名関数をプロパティに配置して、あたかもそれらを呼び出すことができます。それらはメソッドでした。以前のバージョンのプロパティに無名関数を配置することはできますが、少なくともPHP 5.3の時点では、これらの関数は参照できない$this
ため、オブジェクトの一部としてはまったく役に立ちません。この制限は、現在同じことを達成するために魔法の方法を使用する__call
ことを妨げるものでもあります。
第四に、これは完全に答えではありません。この種のクラスを曲げる体操が必要な場合は、RubyまたはPerlを検討してください。Pythonでも同様のことができると思いますが、私はPythonで作業したことがなく、確信が持てません。PHPはOOに関しては柔軟な言語ではなく、内部リストの人々はOOを他の言語のより興味深い標準に引き上げることに関心がありません。
関連する問題に関しては、インスタンスレベルの特性が本当に必要なようです。PHP 5.4にも特性がありますが、インスタンスレベルではなく、クラスレベルです。それについての私の解説については#4を参照してください。