HOME>WEBプログラム覚書>PHP4 func_get_args()とforeachと参照

PHP4 func_get_args()とforeachと参照

まだまだPHP4は現役ですね。 久しぶりにPHP4でコード書いてたら肝心なところがコピー扱いでハマりました。

テストコード

PHP

  1. <?php
  2. class Man
  3. {
  4.     var $name;
  5.     var $comment;
  6.  
  7.     function Man($name, $comment)
  8.     {
  9.         $this->name = $name;
  10.         $this->comment = $comment;
  11.     }
  12.  
  13.     function view()
  14.     {
  15.         printf("<h5>「%s」 - %s -</h5>", $this->comment, $this->name);
  16.     }
  17. }
  18.  
  19. class Mens
  20. {
  21.     var $mens = array();
  22.  
  23.     function Mens()
  24.     {
  25.         foreach (func_get_args() as $man) {
  26.             $this->mens[] =& $man;
  27.         }
  28.     }
  29.  
  30.     function view()
  31.     {
  32.         foreach ($this->mens as $man) {
  33.             $man->view();
  34.         }
  35.     }
  36. }
  37.  
  38. $man_1 = new Man("ハリ美jyun", "俺はもう既に本物のヒョウなのかもしれない");
  39. $man_2 = new Man("JMC パンサー", " 3秒だ。野郎を倒すのも女をオトすのもな");
  40. $man_3 = new Man("サイバー田中", "俺の行き先?あの太陽にでも聞いてくれ");
  41.  
  42. $mens = new Mens($man_1, $man_2, $man_3);
  43. $mens->view();
  44.  
  45. var_dump($man_1 === $mens->mens[0]);
  46. var_dump($man_2 === $mens->mens[1]);
  47. var_dump($man_3 === $mens->mens[2]);
  48. ?>

実行結果

「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
bool(false) bool(false) bool(true)

なんじゃいこりゃ!?

func_get_args()では参照渡しができない

上記ページに書かれているようにfunc_get_arg()は参照に対応していないので array()でまとめて渡すようにします。

PHP

  1. <?php
  2. class Man
  3. {
  4.     var $name;
  5.     var $comment;
  6.  
  7.     function Man($name, $comment)
  8.     {
  9.         $this->name = $name;
  10.         $this->comment = $comment;
  11.     }
  12.  
  13.     function view()
  14.     {
  15.         printf("<h5>「%s」 - %s -</h5>", $this->comment, $this->name);
  16.     }
  17. }
  18.  
  19. class Mens
  20. {
  21.     var $mens = array();
  22.  
  23.     function Mens(&$mens)
  24.     {
  25.         foreach ($mens as $man) {
  26.             $this->mens[] =& $man;
  27.         }
  28.     }
  29.  
  30.     function view()
  31.     {
  32.         foreach ($this->mens as $man) {
  33.             $man->view();
  34.         }
  35.     }
  36. }
  37.  
  38. $man_1 = new Man("ハリ美jyun", "俺はもう既に本物のヒョウなのかもしれない");
  39. $man_2 = new Man("JMC パンサー", " 3秒だ。野郎を倒すのも女をオトすのもな");
  40. $man_3 = new Man("サイバー田中", "俺の行き先?あの太陽にでも聞いてくれ");
  41.  
  42. $mens = new Mens($mens = array(&$man_1, &$man_2, &$man_3));
  43. $mens->view();
  44.  
  45. var_dump($man_1 === $mens->mens[0]);
  46. var_dump($man_2 === $mens->mens[1]);
  47. var_dump($man_3 === $mens->mens[2]);
  48. ?>
実行結果
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
bool(false) bool(false) bool(true)

変化なし。というかそもそもなんで全部最後のオブジェクトになってるの?? なんかそっちが気になってきました。

foreach は参照ではなくコピー

上記ページでdisられてるようにforeachはコピーとなります。 残念ながらforで対応するしかないようです。

PHP

  1. <?php
  2. class Man
  3. {
  4.     var $name;
  5.     var $comment;
  6.  
  7.     function Man($name, $comment)
  8.     {
  9.         $this->name = $name;
  10.         $this->comment = $comment;
  11.     }
  12.  
  13.     function view()
  14.     {
  15.         printf("<h5>「%s」 - %s -</h5>", $this->comment, $this->name);
  16.     }
  17. }
  18.  
  19. class Mens
  20. {
  21.     var $mens = array();
  22.  
  23.     function Mens(&$mens)
  24.     {
  25.         for ($i=0; $i<count($mens); $i++) {
  26.             $this->mens[] =& $mens[$i];
  27.         }
  28.     }
  29.  
  30.     function view()
  31.     {
  32.         for ($i=0; $i<count($this->mens); $i++) {
  33.             $this->mens[$i]->view();
  34.         }
  35.     }
  36. }
  37.  
  38. $man_1 = new Man("ハリ美jyun", "俺はもう既に本物のヒョウなのかもしれない");
  39. $man_2 = new Man("JMC パンサー", " 3秒だ。野郎を倒すのも女をオトすのもな");
  40. $man_3 = new Man("サイバー田中", "俺の行き先?あの太陽にでも聞いてくれ");
  41.  
  42. $mens = new Mens($mens = array(&$man_1, &$man_2, &$man_3));
  43. $mens->view();
  44.  
  45. var_dump($man_1 === $mens->mens[0]);
  46. var_dump($man_2 === $mens->mens[1]);
  47. var_dump($man_3 === $mens->mens[2]);
  48. ?>
実行結果
「俺はもう既に本物のヒョウなのかもしれない」 - ハリ美jyun -
「 3秒だ。野郎を倒すのも女をオトすのもな」 - JMC パンサー -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
bool(true) bool(true) bool(true)

とりあえず期待通りの出力になりました。 ほんとに参照になってるか確認してみます。

上記コードに下記を追加

PHP

  1. <?php
  2. $man_1->name = "TEST";
  3. var_dump($mens->mens[0]->name);
  4. ?>
実行結果
string(4) "TEST"

ちゃんと参照となっているようです。

PHP4 におけるオブジェクトの比較

最初の例から === が不穏なtrue返してたんで調べてみたら PHP4ではオブジェクトの比較は == も === も差がないとのこと。

PHP4では、とてもシンプルな作法でオブジェクトを比較できます。すなわち、 二つのオブジェクトは同じ属性と同じ値を持ち、 同じクラスのインスタンス である場合には等しいのです。二つのオブジェクトを比較演算子 (===)で比較した場合でも同様のルールとなります。

PHP: におけるオブジェクトの比較 - Manual

mens配列の要素をコピーにしてみます。

PHP

  1. <?php
  2. class Man
  3. {
  4.     var $name;
  5.     var $comment;
  6.  
  7.     function Man($name, $comment)
  8.     {
  9.         $this->name = $name;
  10.         $this->comment = $comment;
  11.     }
  12.  
  13.     function view()
  14.     {
  15.         printf("<h5>「%s」 - %s -</h5>", $this->comment, $this->name);
  16.     }
  17. }
  18.  
  19. class Mens
  20. {
  21.     var $mens = array();
  22.  
  23.     function Mens(&$mens)
  24.     {
  25.         for ($i=0; $i<count($mens); $i++) {
  26.             $this->mens[] =& $mens[$i];
  27.         }
  28.     }
  29.  
  30.     function view()
  31.     {
  32.         for ($i=0; $i<count($this->mens); $i++) {
  33.             $this->mens[$i]->view();
  34.         }
  35.     }
  36. }
  37.  
  38. $man_1 = new Man("ハリ美jyun", "俺はもう既に本物のヒョウなのかもしれない");
  39. $man_2 = new Man("JMC パンサー", " 3秒だ。野郎を倒すのも女をオトすのもな");
  40. $man_3 = new Man("サイバー田中", "俺の行き先?あの太陽にでも聞いてくれ");
  41.  
  42. // arrayの要素をコピーにしてみる。
  43. $mens = new Mens($mens = array($man_1, $man_2, $man_3));
  44. $mens->view();
  45.  
  46. var_dump($man_1 === $mens->mens[0]);
  47. var_dump($man_2 === $mens->mens[1]);
  48. var_dump($man_3 === $mens->mens[2]);
  49.  
  50. $man_1->name = "TEST";
  51. var_dump($mens->mens[0]->name);
  52.  
  53. var_dump($man_1 === $mens->mens[0]);
  54. ?>
実行結果
「俺はもう既に本物のヒョウなのかもしれない」 - ハリ美jyun -
「 3秒だ。野郎を倒すのも女をオトすのもな」 - JMC パンサー -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
bool(true)
bool(true)
bool(true)
string(13) "ハリ美jyun"
bool(false)

確かにコピーなのにtrueとなってますね・・・

うーんPHP4で同じオブジェクトか調べるにはどうしたらいいんでしょうか?

PHP5では改善されてます。

上記の2点はPHP5では改善されてます。最初のコードの =& を = にすれば問題なく動きます。やったね。

PHP

  1. <?php
  2. class Man
  3. {
  4.     var $name;
  5.     var $comment;
  6.  
  7.     function Man($name, $comment)
  8.     {
  9.         $this->name = $name;
  10.         $this->comment = $comment;
  11.     }
  12.  
  13.     function view()
  14.     {
  15.         printf("<h5>「%s」 - %s -</h5>", $this->comment, $this->name);
  16.     }
  17. }
  18.  
  19. class Mens
  20. {
  21.     var $mens = array();
  22.  
  23.     function Mens()
  24.     {
  25.         foreach (func_get_args() as $man) {
  26.             $this->mens[] = $man;
  27.         }
  28.     }
  29.  
  30.     function view()
  31.     {
  32.         foreach ($this->mens as $man) {
  33.             $man->view();
  34.  
  35.         }
  36.     }
  37. }
  38.  
  39.  
  40. $man_1 = new Man("ハリ美jyun", "俺はもう既に本物のヒョウなのかもしれない");
  41. $man_2 = new Man("JMC パンサー", " 3秒だ。野郎を倒すのも女をオトすのもな");
  42. $man_3 = new Man("サイバー田中", "俺の行き先?あの太陽にでも聞いてくれ");
  43.  
  44. $mens = new Mens($man_1, $man_2, $man_3);
  45. $mens->view();
  46.  
  47. var_dump($man_1 === $mens->mens[0]);
  48. var_dump($man_2 === $mens->mens[1]);
  49. var_dump($man_3 === $mens->mens[2]);
  50.  
  51. $man_1->name = "TEST";
  52. var_dump($mens->mens[0]->name);
  53.  
  54. var_dump($man_1 === $mens->mens[0]);
  55. ?>
実行結果
「俺はもう既に本物のヒョウなのかもしれない」 - ハリ美jyun -
「 3秒だ。野郎を倒すのも女をオトすのもな」 - JMC パンサー -
「俺の行き先?あの太陽にでも聞いてくれ」 - サイバー田中 -
bool(true) bool(true) bool(true) string(4) "TEST" bool(true)
投稿日 2009年7月28日 11:48
カテゴリ PHP
タグ テストコード | 言語仕様
トラックバック URL http://www.kantenna.com/cgi-bin/mt504/mt-tb.cgi/1179

コメント

コメントする
Name
Email Address
URL