2009年1月5日 月曜日 21:24:04

PHPクラスの継承でオーバーライドしてしまった値を取得!

メモ,プログラム,php,WEB開発 [ by Mizugame ]

ソース-オブジェクトをキャスト
あけましておめでとうございます(>_<)
なんだかんだで、ずるずると公開から2回目の新年を迎えてしまいました!

結構な勢いで更新さぼっちゃいましたが、今年もよろしくお願いいたします!!!

と、本題。

少し前にPHPプロの質問で、「親クラスのメソッドをクラス外から呼びたい」って質問があがっていました。

オブジェクトを配列へキャストするとこうなるんだぁ・・・( ̄□ ̄;)
オーバーライドで上書きしちゃってても、プライベート変数だっても関係ないじゃん・・・っていう話。

質問が解決されてから日が経っちゃってるけど、完全に忘れる前にメモ。

というわけで、自分の中では驚愕の事実だった手法は以下から。

紹介されていたコード

どうやらPHPUnit内の処理を参考にされた模様。

<?php 

/**
 * privateな属性の値を参照する。
 * 参考: PHPUnit_Framework_Assert::getObjectAttribute($object, $attributeName)
 */
function get_private_value($obj,$attributeName,$class=false) {
  if( $class===false) {
    $class = get_class($obj);
  }
  $objArray = (array) $obj;
  $privateName = sprintf("%s%s",$class,$attributeName);
  if( array_key_exists($privateName,$objArray) ) {
    return $objArray[$privateName];
  }
  return null; 

}
  $test=new testClass3(); 

  $ret = get_private_value($test,'a','testClass3');
  var_dump($ret);
  $ret = get_private_value($test,'a','testClass');
  var_dump($ret); 

?>

まぁ、これだけだと途中の処理が省略されて、何をやってるのか分からないから、簡単にまとめます。

まとめ

まずプライベート変数を持った親クラスを作り、オーバーライドさせるために同じ名前のプライベート変数を持たせた子クラスで継承させる。

<?php
//親クラス
class ParentClass {
  private $value = 'ParentClass Value!';
}
//子クラス
class ChildClass extends ParentClass {
  private $value = 'ChildClass Value!';
}
?>

余計なことは省いて変数を上書きするだけ。

で、オブジェクトを作ってから配列にキャスト!(゜∀゜)

<?php
$object = new ChildClass();
var_dump((array)$object);
?>

ドキドキの結果は・・・。

array(2) {
  ["ChildClass�value"]=>
  string(17) "ChildClass Value!"
  ["ParentClass�value"]=>
  string(18) "ParentClass Value!"
}

うわーーーー∩(≧∇≦)∩
なにか気持ち悪いものが見えてるけど、各プライベート変数が存在する配列になってるっぽい!

それから元記事で紹介されている

sprintf("%s%s",$class,$attributeName);

を参考に、質問者の方が回答されている実用的(?)な方法で記述すると。

<?php
$object = new ChildClass();
$arrayObject = (array)$object;

echo "ParentClass Value : ",
  $arrayObject["ParentClassvalue"],
  "nChildClass Value : ",
  $arrayObject["ChildClassvalue"];
?>

ワクワクの結果は・・・。

ParentClass Value : ParentClass Value!
ChildClass Value : ChildClass Value!

うはぁ(>▽<)/
取り出せたよ!!!

PHPすげぇ(>_<);;;
全く使い所がわかんねぇ!!!

すごいんだけど、こういう力技が必要になった時点で設計ミスってる気が・・・。

質問内容もスゴイけど、解決できちゃうところがスゲェ!
・・・そうかぁ、オブジェクトは配列にキャストかぁ(´・ω・`)

PHP4あたりではget_object_varsなんかを使って、メンバー変数を確認したりはしたけど、プライベートとか抜き出せないし、まぁメンバー変数を上書きしちゃったら1つの変数だしで、ちょっとどうしようもなかったんだけど。

まだまだPHPには未知の領域が存在しそうです(゜∀゜)

追記(2008-1-5 21:34:12):
オブジェクトをarrayにキャストする – Do You PHP はてな
うはぁ、わりと有名なのかな(>_<)
いろいろスゲェ。

関連記事:
JavascriptでindexOfとmatchの速度がちょっと気になった
[MDIEスクリプト] select2zip.jsを更新

コメント (2) »

1. の4
コメント :: 2009年1月14日 水曜日 @ 116:53:48

すごいっすね!
でもこれ使う場合は確かに設計ミスのような気がしますね(汗)
親要素のprivateフィールドを取得するのはオブジェクト指向で必要なのかどうか……

2. Mizugame
コメント :: 2009年1月15日 木曜日 @ 22:43:19

こんにちは。

ほんとスゴイですよ。

「\0」とか入ってるところからも、全然想定してない使い方なのでしょうけど。

わざわざ差し替えた値をやっぱり呼びたくなった・・・なんてなかなか無いと思うんで。

どっちにしても、上書きしたくないなら各オブジェクトにプロパティとして持たせるべきだと思うんで、動いているサービスには極力差し込みたくない処理ですね。

PHP仕様が変わって、バージョンアップと同時におかしくなったとかがあっても嫌ですし。