$data = ActiveRecord::find($key);
$data->update = true;
$data->save();
たまーに、「stdClassなのでsaveメソッドが無いよ」と言われる。いやあ悩みましたね。
カラクリはこうです。
- $dataがnullで戻ってくる
- 2行目の代入直前に、$data = (object)$data というキモい型変換をやってのける
- 当然saveメソッドなんて有るわけない。
- ←いまココ
スカラー同士の型変換はまだいいとして、オブジェクトに変換はイラネーだろと。Zendエンジンにパッチ当てて、型変換を辞めさせようかと真剣に悩みましたよ。でもZendのソースはキモいので、正直触りたくない。
ちなみに逆変換もまた酷いことになります。
- $data = (object)ナニカ
- $name = "$data";
- $data が "Object"とか入ってる。
- ←いまココ
- 構文。すなわちZendコンパイラが腐ってる
- 実行時。すなわちZendエンジンが腐ってる。
- 主に暗黙の型変換のセンスが悪い。
- 内蔵ライブラリが腐ってる。
構文に関してはかなり致命的です。
- プログラムのファイル間の結合方法がincludeしかない。requireはincludeの延長線上の機能なのでこれに含みません。
- 実はinclude文は、バイトコードエンジンの範疇だったりする。故に「実行時インクルード」というキモい挙動。
- クラスプロパティの区切り文字と、名前空間階層の区切り文字に、別の文字を使ったところ。前者はダブルコロン。後者はバックスラッシュ。なんで?
- 構文解析がタコいから?
- 確かにこれ以前までは、バックスラッシュは文字列定数にしか現れません。だからって、記号の質を変えて良いって訳ではない。
- ディレクトリ区切りにバックスラッシュを使ってるWindowsは、(PHPと同じく)腐ってるわけですが
- 連想配列の初期化構文。
- 中括弧を使わないのは、スコープ構文と区別が付かないから?
- 関数の参照渡しがない。
- array( & $this, $method )とか、こんなモノ第一級関数とか呼ばないデスヨ。↓後述
- is_callable("mb_convert_encoding") == true とか馬鹿じゃねえのかと。
- new演算子の直後で、直接メソッドを使えない。
- 恐らく、表面上はnewは演算子の体裁をしつつも、実は別系統の構文なのではないか?と勘ぐってますが。ソースは読んでません。
- use文のキモい用法
- 名前空間のインポート?
- 挙句、mix-inのインポート?
- class定義内で、static変数やconst定数を、変数式で初期化できない。
- 定数式でなら初期化できます。
- メンバ変数の初期化構文は、「コンパイラの仕事」だから。
- 文字列専用の連結演算子が "."
- 内蔵ライブラリ関数が0とfalseとnullを混在して返すこと。しかもそれぞれ意味が異なる。
- 世間一般には例外を投げるところです。が、今から変更することは恐らくないでしょう。何故なら、戻り値を===で判定しちゃってるプログラムが山の用にあるからです。
- 前述の通り、スカラ型から、オブジェクトへの「型変換」は出来るが、出来上がったインスタンスはstdClassで、しかもこれはオブジェクト群の「基底クラス」では「ない」
- 故に、折角のタイプヒンティングがあるのに「兎に角、任意のオブジェクト」を示す方法がない。stdClassと書くと「無名オブジェクトしか」引っかからない。
- 自前のクラスを定義する時に、extend stdClassと書けば良いのだが。こんなの馬鹿じゃねえのかと。
- new stdclassは出来る。
- includeしかありません。
- include文は、zendエンジン上で、それに相当するバイトコードがあります。
- 実は、eval( file_get_contents() ) と同義だったりします。
- 故に、大規模なプログラム開発には、本質的には向かない。毎回コンパイルしてるので。
- Java族が言う所の「PHPは遅い」はこの辺りに起因してると思うのですが、PHPのコンパイル自体は意外なほど早かったりします。要はプログラムの規模次第ってことでしょう。
- この構造故に、class定義の間でincludeを使っても、期待通りには動きません。
- 第1級関数が無い
- 5.3では、無名関数のためにClosureオブジェクトというのを内部で使ってるっぽい。create_functionした結果をvar_dumpすると、そう表示する、しかし
- コンパイラ側にclosureの定義がない。function method1( closure $func1 ) とか書けない。馬鹿じゃねえのかと。
- 故に、組み込み関数の渡すときは、文字列定数で渡すしかない。
- $a = "echo" ; is_callable($a) == true とか馬鹿じゃねえのかと。
こんな駄目言語でも、仕事では使わざるを得ません。しかし、前述の通りの穴だらけ仕様なので、「安全」というか「バグりにくい」プログラムを書く方法はそんなに多くありません。
- 関数の戻り値は
- 常に同じデータ型で返す。しかも成功時のみ。
- 失敗時は
- やはりオブジェクト型で返す。例えばデータが見つからなければ 「「データが見つからない」を示すオブジェクト」をnewして返す。
- 何故って、PHPが別の型に変換しやがった時に、迷宮入りする可能性が低いから
- throw しまくる
- データが見つからなければ、「データが見つかりません例外」を投げるべき。
- 空の配列を返すとかだと、count()==0とかやらなければならなくなる。でもそれは空文字でもヒットするので、実はジワジワ危険だったりする。
- is_array($result) && count($result)==0 とか馬鹿じゃねーのかと。