今日また新たな糞仕様を知ったよ
今回使ったPHPのバージョン
$ php --version
PHP 5.3.6-13ubuntu3.3 with Suhosin-Patch (cli) (built: Dec 13 2011 18:18:37)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies
<?php
$array = array(1,2,3);
$ref = &$array[1];
$copy = $array;
$copy[0] = 'a';
$copy[1] = 'b';
$copy[2] = 'c';
foreach( $array as $v ) {
print "${v}\n";
}
?>
$ php -r '$array = array(1,2,3); $ref = &$array[1]; $copy = $array; $copy[0] = "a"; $copy[1] = "b"; $copy[2] = "c"; foreach( $array as $v ) { print "${v}\n"; }'
1
b
3
5行目で配列の2番目の要素の参照を他の変数に渡してるのが原因なんだろうけど
なんでこうなるの?誰かPHP使いに説明してほしい。
てゆうか配列の入った変数を他の変数に代入すると値がコピーされるのもワロスなポイント
PHPの配列はCの構造体みたいな扱いなんだろうか?
いずれにしてもそんな仕様のメジャーな言語は見たことが無い
自分を疑ってみる
自分が期待する結果は1、2、3だけど
ひょっとしたら自分のポインタ操作に対する知識がおかしいのかもしれない
ということで同じようなコードをCで書いてみる
#include <stdio.h>
#include <string.h>
int main() {
#define ARRAY_LEN (3)
char array[ARRAY_LEN] = {'1','2','3'}, copy[ARRAY_LEN], *ref;
int i;
ref = &array[1];
memcpy( copy, array, ARRAY_LEN );
copy[0] = 'a';
copy[1] = 'b';
copy[2] = 'c';
for( i=0; i<ARRAY_LEN; ++i ) {
printf( "%c\n", array[i] );
}
return 0;
#undef ARRAY_LEN
}
$ gcc test.c
$ ./a.out
1
2
3
期待通りの結果になってホッとした
当然だがstrcpyする前に*ref = 'b';とすればphpと同じ結果になる。
ではPHPでは何が起きているのか?
怪しいコードの前後でvar_dumpしてみることにした
<?php
$array = array(1,2,3);
var_dump( $array );
$ref = &$array[1];
var_dump( $array );
?>
$ php -r '$array = array(1,2,3); var_dump( $array ); $ref = &$array[1]; var_dump( $array );'
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(1)
[1]=>
&int(2)
[2]=>
int(3)
}
・・・???
他の変数にポインタを渡したら右辺値が型変換されたってこと・・・?
わけがわからないから、配列の要素ではなく普通の変数を渡してみる。
<?php
$v = 1;
$ref = &$v;
var_dump( $v );
?>
$php -r '$v = 1; $ref = &$v; var_dump( $v );'
int(1)
・・・???
今度は変換されなかった・・・・なんで?????
じゃあこれはこれは??
<?php
$a = 1; // $a は 1
$b = &$a; // $b は $a の参照
$c = $b; // $c はどうなる?
$c = 2;
print "${a}\n"; // これが1なら$cは参照、2なら$cは値ということになる
?>
$ php -r '$a = 1;$b = &$a;$c = $b;$c = 2;print "${a}\n";'
1
???
今までの流れでいくと$cには$aの参照が渡されるはずなんだけど、このケースでは値が渡されるようだ
わけがわからないけど、つまり
配列の要素のポインタを他の変数に代入すると、その要素の型はポインタ型に変換される
という仕様がPHPにはあるのだと思う。
(゚Д゚)ハァ?
ちなみにこのようなケースでは
<?php
class Test {
public $a = 1;
public $b = 2;
public $c = 3;
public function &get_b_ref() {
return $this->b;
}
};
$obj = new Test();
$b_ref = &$obj->get_b_ref();
var_dump( $obj );
$copy = clone $obj;
$copy->a = 'a';
$copy->b = 'b';
$copy->c = 'c';
var_dump( $obj );
?>
$ # 今回のコードは少し長いのでファイルに書いて実行
$ php test.php
object(Test)#1 (3) {
["a"]=>
int(1)
["b"]=>
&int(2)
["c"]=>
int(3)
}
object(Test)#1 (3) {
["a"]=>
int(1)
["b"]=>
&string(1) "b"
["c"]=>
int(3)
}
当然・・・$obj->bの値は"b"である
おれたちにできない事を平然とやってのけるッそこにシビれる!あこがれるゥ!
はい、ということでまとめ
こんな糞言語誰が好き好んで使ってんだろう
PHPを好きって言ってる人は「PHPしか書けない」「PHPしか知らない」
あとは「見た目がC言語っぽい」とかいう理由で書いたことも無いような人
それぐらいだと思う。
「初心者に書きやすい」とか「学習コストが低い」とかいう触れこみの書籍が沢山出てWEBのブームと共に人気が出てたけど
こんな糞言語から入ったプログラマーが本当に使い物になるのか疑問だ
あの時大量生産されたsqlインジェクション可能なwebアプリは今どうなっているのだろうか?
今からなにかプログラム言語を学ぼうって人がいたらPHP、C++、VBなどの糞言語はやらないほうがいい
最初に選ぶ言語で1年後2年後に出来ることに大きな差が出ると思う
とりあえず何個か普通の言語を覚えて
きっちり書きたいときはC、JAVA、Python
ゆるく使いたいときはC#、Ruby、Perl
プログラミングという行為自体で遊びたいときはHaskell、Scala、Clojure
などの使い分けをするのがよいと思う