ラベル hate php の投稿を表示しています。 すべての投稿を表示
ラベル hate php の投稿を表示しています。 すべての投稿を表示

2019年6月16日日曜日

PHPどうにも駄目な理由

出稼ぎ先で「もうPHP使いたくないです」と言ってからはや3ヶ月。
かなり試行錯誤したお陰で、PHPの弱点が明確に判った。

先月書いたエントリとも重複する。
とはいえこれらが問題になるのは、1000行以上の処理を書くようになってからだろう。
数行でレスポンスを繰り返すなら問題はほとんど表面化しない。

クラス定義がコンパイル時なのに<紛い物のOOP
ソース結合がランタイムであること<依然として「歯ブラシ
そのためにシンボル結合がランタイム+文字列であること

端的に言えば、スペルミスすら動かしてみないと判らない、ということだ。

オブジェクト指向を名乗っておきながら
メソッドの定義はクラスの内側に書くしか無い<オブジェクト指向をやりたければ必然ファイルが長くなる
ファイル分割するならトレイトを使うしか無い<後発の言語には大概拡張メソッドがある
にもかかわらずモジュール結合はランタイム。

クラスメンバ変数の初期化の方法が少ない。
getter setterの構文が存在しない<マジックメソッドは実行時結合。あんなものは機構とは言わない。

コンストラクタで書くのが一般的だが、引数が増えれば増えるほど順序間違いを防ぐの非常に困難になる。
変数への代入をタイプミスしても、エラーにならないどころか勝手に定義されてしまう。

ジェネリックが無い。
PHPの基本型はどうかんがえても連想配列である。
クラスは前述の通り非常に扱いが不便だからだ。オブジェクト指向なんて嘘っぱちだ。
にもかかわらず、連想配列の中身を担保する方法が存在しない。

これらはC言語の延長線上のようなコーディングをするなら全く問題にならない。
複雑なオブジェクト指向を書こうとすると途端にあれこれ邪魔になる。
しかしそんなもので開発効率があがるわけがない。

では、10年前にヤフー等がPHPを採用した理由は何だったのか?
見てご覧よこの得意げなタイトルを。ドヤ顔が見えるようだ。顔知らんけど。

PHPとYahoo!の意外なカンケイ - Yahoo! JAPAN Tech Blog https://techblog.yahoo.co.jp/web/auctions/phpyahoo/

テキトーに書いてもある程度まで処理継続してくれる。それによる試行錯誤だろう。
それ以上を期待すると途端に裏切られる。現に、今ではJava/kotlinを採用してるようだ。

Yahoo!カレンダーがPHPからKotlinに技術移行し品質アップ! 成功の鍵とは?【デブサミ2018 関西】 (1/2):CodeZine(コードジン) https://codezine.jp/article/detail/11144

なぜYahoo!カレンダーはPHPからKotlinへ技術移行を進めるのか / Devsumi 2018 KANSAI A-4 https://www.slideshare.net/techblogyahoo/yahoophpkotlin-devsumi-2018-kansai-a4-117060700

ヤフーにおけるJava事情を軽くご紹介します - Yahoo! JAPAN Tech Blog https://techblog.yahoo.co.jp/bb/yahoo-java-usage-introduction/


2019年5月5日日曜日

PHP7も相変わらずウンコでビビった話

ここ丸1年ほど、ガッツリPHP7.2を触ってたが、あーもーこの言語駄目だ。とようやく明確に認識した。

もっとも大きいのは次の点だろう。

  • クラス定義がコンパイル時なのに<紛い物のOOP
  • ソース結合がランタイムであること<依然として「歯ブラシ」
例えば、クラスのstatic変数初期化に式を使いたいと思ったことない?それが出来ないのはコンパイル時クラス定義のせいだ。また同じ理由で、関数&クラス定義はスコープを貫通する。

端的に言えば、動的言語を標榜してるくせにちっとも動的じゃねえよってことだ。
これのお影で、仕様変更に弱い実装しか出来ない。非常に頑張りにくい。

例えば、既に出来上がってテストも済んでるソースに何か機能追加するには、そのファイルを修正するか、継承してほげほげするしかない。

前者は再テストが必要だし、後者は別のクラスになるため各処理の参照先を変えるのがかなりの手間。

であるにも関わらず、require/includeの元ファイルはすでにコンパイル済で、include先はこれから慌ててコンパイルする。故に、このinclude/requireを組み合わせて、動的にクラス生成管理をすることが出来ない。

後発の言語には、これらを援護する手段が大抵付いている。具体的には拡張メソッドがそれだ。PHPに拡張メソッドを付けるRFCが出てたけど、あれがどんなに役立つか知らんの、複雑な案件をやらされたことがありませんと言ってるようなものだ。

拡張メソッドっぽい記述はPHPでも __callとcall_user_func_argsを使えば実装は可能だ。が、可能だというだけで、これまたランタイム結合なので、これまた実行するまで関数名間違いに気づかない。IDEの恩恵を微塵も受けられない。static/裸function を呼ぶのといい勝負、って話になりかねん。

出稼ぎ先で、毎案件フルスクラッチから書いてるの馬鹿じゃねえのと思ってたけど、PHP使ってる限りは仕方ない。PHPを卒業するのが先だ。

2015年3月8日日曜日

PHP 好きとか嫌いとかじゃなくて、「危なっかしい」んだよな

小生はアンチPHPですが、「好きか嫌いか」で言われるとどっちでもありません。副流煙みたいなものですよ。故に「嫌いだからPHP使わないんだろ!」とか言われると心外です。 そもそもPHPが好きって有り得るのか?原作者自身が歯ブラシと言ってる代物なのに?

日経ソフトウエア4月号でPHPの紹介記事がありました。
  • XAMPPのお陰で導入が楽
  • HTML文書にPHPのコードを書き込める
  • 変数を宣言しなくてよい
  • XAMPPにはMySQLが入ってる(のデータベース管理システムを簡単に使える
  • IDEも入手しやすくなってきた

これら自体は否定はしないし、PHPの魅力ではあるでしょう。しかし、これらの殆どがバグを産む原因でもあるというジレンマ。

PHPの原作者自身が「歯ブラシだ」と言ってるのでそれ以上を望むのは無意味でしょう。便利さが全て。歯ブラシは頑固な汚れを取るのにも重宝します。

PHPが致命的にマズイと思ってる理由は、現状では次の点です。

HTMLの「間」に書く言語であることがマズイ。


これのお陰で「Webアプリケーションがササッと作れる」それは否定しない。しかしそれは工夫しないと非常に読みにくいプログラムが出来上がる。別の側面から言えば、「標準出力に出力する方法が多すぎる」

  • include/requireでHTMLファイルを読む
  • echo等
  • PHPタグを一旦閉じて開ける
どいつもこいつも見にくく、そして「取りあえずソレで動いてしまう」が故に「テンプレートエンジンの利用に踏みきれない」理由でもある。

「Webアプリケーション」なら致命的になることはあまりありません。それなりに動く。ところがRPCサーバを作ろうとすると途端に邪魔になります。warningメッセージがぼろぼろレスポンスに混ざるので、リクエスト側プログラムがparseに失敗する。

display_errors=0にしとけって?その通り。そしてそれはPHPの標準設定が初心者向きであることを意味しています。

include先にPHPプログラムを書く場合は、PHPタグを「閉じない」場合が大多数でしょう。うっかり閉じると、その直後の改行を勝手にレスポンスに入れちゃって、リクエスト側プログラムがparseに失敗する。

前述の通り「include先が「PHPプログラムである」こと」をPHPは既定してません。HTMLでもテキストファイルでも構わないのです。故にぱっと見何のためのincludeだか判らないことになります。もちろんフツウに作ればそんな馬鹿なことにはなりません。でも駄目プログラマがそうすることをPHPは止めません。

しかもこの仕様のお陰で、PHP の include/requireは、他の言語とくらべてもかなり独特の挙動をします。「コンパイル時にソースプログラムをincludeの位置に展開してる」わけでは無い」のです。

実はPHPのバイトコードに、include命令があります。includeは実行時展開なのです。そりゃそうだ。でなければファイル名に変数を使われた時に対応できなくなる。 これは動的にHTMLを切り替える時に必要な挙動です。アッタマイイデスネ。

以上の小生の主張を、裏付けてくれるかのようなソースがありました。
かの有名なWordPressそのcaptchaプラグイン。

http://plugins.svn.wordpress.org/captcha/tags/2011.2.11/captcha.php

いつの間にかPHPが終わって、いつの間にかHTMLが始まってる。
それだけが原因では無いでしょうが、そりゃセキュリティ問題も出るでしょうよと

http://www.itmedia.co.jp/enterprise/articles/1503/03/news092.html

勝手に型変換するのがマズイ

PHP7.0で漸く改善しました。

変数の中身型をあえて特定しないスタイルをダックタイピングとか読んだりしますが、PHPの不味さはソコではない。勝手に型変換をするところです。数値と文字列を読み替える程度ならまだいいでしょう。クラスや配列まで相互変換できてしまうのです。

http://php.net/manual/ja/language.types.type-juggling.php

型の間でキャストを行う際の動作は、必ずしも明確ではありません。 詳細については、以下の節を参照ください。
ここ、笑うところですよ。プログラム言語の挙動を明確に定義できないとか、どういうことかって話よ。

初心者向きとしては悪くない挙動です。中級者になると途端に裏切られる。トリプルイコールを徹底するのも手ですが、今度は型違いでエラーすら起こらなくなるので、よほど慎重に書かないと迷宮入りが早くなる可能性がある。

関数呼び出しの引数が足りなくてもwarningにしかならないのがマズイ

PHP7.1で漸く解消しました。

Warningにしかならない。仮引数にはシレっとnullが入る上に、これは0にもfalseにも空文字にも勝手にキャストし得る値です。

PHPのWarningは、他の言語であればFatalであるものが殆どです。この点を踏まえて、set_error_handlerで自前のハンドラを用意して選別して、場合によっては例外として投げ直して死なすのが「プログラマの生活の知恵」ってところでしょう。こんな使いにくい歯ブラシがありますか?

関数のタイプヒントには極力array/クラス名を指定するべき。これであれば引数が足りない場合にCatchable fatal Exceptionになります。

スーパーグローバル変数のお陰で、外部からの入力をプログラムの奥で何時でも参照できるのがマズイ

典型的な例を発見

Analysis of the Fancybox-For-WordPress Vulnerability
 http://blog.sucuri.net/2015/02/analysis-of-the-fancybox-for-wordpress-vulnerability.html

WordPress本体が頑張っても、プラグインがろくにチェックもせずに$_REQUESTを使ってればこうなるという好例。

もちろん $_REQUESTとかを一旦unsetして再定義すれば、非スーパーグローバルになるので比較的安全に扱えます、が、そこまでさせるなって話ですよ。


何れの項目に関しても、声を大にして言いたいのは、

いや、そこは例外吐いて死んどけよ。

(もちろんHTMLの話は違いますよ。いちいち言わなくても判りますよね :) )
そもそもphp.iniとかで expertmode = trueとか出きるようにしとけと。

PHPの本質的なヤバさは、
  • 駄目プログラムを書くと、他の部分が容易に巻き添えを食うこと
  • それを防ぐのコストが非常に面倒くさいこと
グローバル変数が、名前空間を貫通することに気づいたときは吹きましたよ。関数名/クラス名のためだけかよ orz この為に迷宮入りしたこともあり。



と言うわけで、「嫌ってる」んじゃなくて「嫌がってる」んだよ!と言おうと思ったけど、どうやら前者は気分で、後者は態度を表現するだけの違いらしい。あまり変わらなかった。

2014年10月28日火曜日

「Rasmus Lerdorf」名言集を聞いたらむしろ嫌PHP厨がファビョる必要なくね?

小生初めてしりました。逆に言うとその程度の興味しかなかったってことですが。
http://anond.hatelabo.jp/20100427231539
ファビョるの云々ということはどうやら煽り文脈らしいが、小生としてはむしろ合点が生きました。

  • 今のPHPを作ったのは、何十人もの開発者ですよ。私は1人目の開発者だったに過ぎません。
  • 問題を解くのが好きなだけで、プログラミングは大嫌いです。
  • いかにプログラミングを避けるかを考えていたら、コードを再利用するためのツールとしてPHPができました。
  • PHPは、歯ブラシみたいなものですね。毎日使うものですけど、だから何でしょう?誰が歯ブラシの本なんて読みたがります?
  • パーザを書くのは苦手です。本当にダメなんです。今でもね。
  • PHPには「protected属性」も「仮想メソッド」もありますよ。情報学科の教官が「重要だ」っていうやつは何でもね。僕自身は、こんなものどうでもいいと思ってますけど。
  • プログラミングを好む人がいるのは知ってますが、全く理解できないですね。
  • 僕はホンモノのプログラマではありませんから、やっつけ仕事ですよ。
  • ホンモノのプログラマは、「動いてるように見えるけど、メモリリークだらけじゃないか。直す必要があるかもね」なんて言うでしょう?僕なら、10リクエストごとにApacheを再起動しますね。
  • いえ、メモリリークはちゃんと気をつけてますよ。でも、プログラミングってほんとクソだなと思いますね。
  • プログラミング言語を作るつもりはありませんでした。どうやって作るのかも知りませんし。論理的に必要だと思われるものを足していっただけなんです。
  • 僕の発言に怒ってる人がいるようですね。僕がプログラマとしてひどいのは認めますけど、でも、多分あなたたちよりマシだと思いますよ(笑)。
もっと早くこれを知るべきでした。であればわざわざこんな事を書く必要もなかった。だってアナタ全部原作者のコンセプト通りだもの。パーザが腐ってるのは不可抗力だったようですが。

http://gihyo.jp/news/interview/2010/rasmus

PHPが、小道具の材料としてある程度使えるのは小生も認めます。間違いはそれを大規模開発に使おうとすることです。原作者がこんな調子なんだから、大規模プログラムに使ってよいわけがない。メモリリーク放置ですよ?

ただし、改めて原作者が「プログラマ」であることを認識しました。「こんな偏屈者がプログラマでないわけがない」何より自分の手間を省くためのプログラミングは圧倒的に正しい。自分の実力を的確に把握してもいるようです。自身をプログラマと呼ばないのはただの謙遜であり弁解でしょう。だから「PHPが駄目言語でも勘弁してよね」とそういうことだ。メンドクサイ奴だなと思いますけどね。

むしろ、嫌PHP厨は、この発言を引っさげて、上司あるいは顧客を説得しましょう。PHPは商用プログラム製品ではないということがハッキリしました。原作者の「賄い」を食わされてるわけです。最初は「ま、オープンソースだから!」で済んだものでしょうが、未だに「賄い感」を維持してるってのは逆に凄い。悪い意味でブレてません。

逆の意味で、Zend社が「PHPで儲ける」のは無理なんじゃね?とも思う。

2012年9月7日金曜日

PHP5.4.6が出てる今更、5.4の新機能について

今更、PHP5.4の新機能を読みました。
http://www.php.net/manual/ja/migration54.new-features.php
いや実は、5.4.xが出てることすら気づかなかったのですが、
厳密にはトレイトをサポートします!とか言ってたころから追ってません。

  • トレイトのサポートが追加されました。
  • 配列の短縮構文が追加されました。$a = [1, 2, 3, 4]; や $a = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4]; のように使えます。
  • foo()[0] のように、関数の返り値を配列として扱えるようになりました。
  • クロージャ が $this をサポートするようになりました。
  • クラスのインスタンスを生成するときに、そのメンバーにアクセスできるようになりました (例: (new Foo)->bar())。
  • Class::{expr}() 構文をサポートするようになりました。
  • 二進数フォーマットが追加されました。0b001001101 のように使えます。
  • パースエラー時のパーサからのメッセージや関数コール時の引数が間違っている場合の警告メッセージが改善されました。
  • セッションモジュールで、ファイルのアップロード状況を追跡できるようになりました。
  • CLI モードで動く、開発用のウェブサーバー が組み込まれました。

それ、pythonで出きるYO。

「トレイト」なるキモい構文は、mix-in専用構文だって話らしいので、恐らく内部的には、「クラス定義のインポート」なんでしょうね。故に重複定義は怒られる。らしい。

新機能を見るかぎり、どうやらZendコンパイラしかイジってなさそう。っと言うことは、ダメ言語である、ということは変わってなさそう。「警告メッセージが改善されました」とか、得意気にいうことじゃねーだろ。 そんもの5.3.Xで終わっとけ。

暗黙の型変換をOFFれるようにしやがれ。話はそれからだ。

そーいえば、PHP5.5ではようやく、generatorをサポートするって、話だし、
http://blog.sarabande.jp/post/30716058960
Javaのパクリの後はpythonですかソーデスカ。

似たようなことはイテレータでも出来ますが、イテレータの方が若干頭を使いますね。逆に言語側の実装は楽になるわけです。ジェネレータはまさしく逆。関数の実行を中断して、次回は続きから実行するとか、言語側の実装は4倍は面倒だと思う。

2012年9月6日木曜日

PHP本体は遅くはない。フレームワークが遅い

今サービス中の別件の案件。

小生が、かなりメモリ使用量に気を遣って書いた箇所は、160request /s出ているらしい。
よく判らないが、検索してみると、これって速いほうですね。
apache+mod_phpのオーソドックスな構成。
ハード構成を言えって?それはここで論じたいネタではないので割愛。

「PHPで性能が出ない!」とお悩みの人を色々検索してみると、
最も典型的なのが「WordPressが」とか。
http://kray.jp/blog/wordpress-tuning/
http://stackoverflow.com/questions/8853692/php-is-slower-than-it-should-be

「性能が出ない」でお困りの皆さん。これらの共通点は、超大作フレームワークの利用。これに尽きます。案件にもよりけりでしょうが、昨今では、

  1. とりあえずフレームワークを使って
  2. 短期間で仕上げて
  3. 性能面はクラウドでどうにかする

なんて手法もアリでしょう。

メイン関数を5行で書けます!という触れ込みで、実はincludeの向こうは5万行を毎回ロードしてますとか。特定のフレームワークの話はしてません。ものの例え、でもそれがPHPフレームワークの本質です。

JAVAであれば、悪い発想ではない。メモリに常駐しまくりなんで。故にスタートアップに10秒かかるとしても。それを「言語仕様がJAVAに似てるだけ」のPHPが真似しよう、ってのがそもそもの間違い。

逆に「クラウドじゃないので、湯水の様には増やせません」と言うなら2択です。

  1. PHPを辞めるか
  2. フレームワークを辞めるか(裸のPHPで書けと)

何故って?

  • 「フレームワーク」は、大量のファイルをincludeし、動的コンパイルを繰り返す。
    • 故に、メモリに常駐しないPHPとは、非常に相性が悪い。
    • ちなみに、adobe AMF frameworkは、3Mb食います。
  • APC等で解決するのは、「コンパイルに要するCPUパワー」だけ
    • 実は、PHPの動的コンパイル速度は、かなり速い。


早い話が、どうしてもPHPを使いたければ、

  • 裸のPHPで
  • 総実行300行未満で
  • メモリ使用量は、標準の8Mbから更に減らして1Mbぐらいでやりくり
でなければ意味がありません。さもなければ結局性能で悩まされるんで。
そんなの書いてられないよって?当たり前です。要するにPHPを使うなって、ことです。

2012年6月4日月曜日

PHPは、未来永劫、駄目言語であり続けると思う

仕事で久しぶりにヤラレましたよ。暗黙の型変換。

$data = ActiveRecord::find($key);
$data->update = true;
$data->save();

たまーに、「stdClassなのでsaveメソッドが無いよ」と言われる。いやあ悩みましたね。

カラクリはこうです。

  1. $dataがnullで戻ってくる
  2. 2行目の代入直前に、$data = (object)$data というキモい型変換をやってのける
  3. 当然saveメソッドなんて有るわけない。
  4. ←いまココ

スカラー同士の型変換はまだいいとして、オブジェクトに変換はイラネーだろと。Zendエンジンにパッチ当てて、型変換を辞めさせようかと真剣に悩みましたよ。でもZendのソースはキモいので、正直触りたくない。

ちなみに逆変換もまた酷いことになります。
  1. $data = (object)ナニカ
  2. $name = "$data";
  3. $data が "Object"とか入ってる。
  4. ←いまココ
PHPの駄目言語たる理由を大別すると、
  • 構文。すなわち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 とか馬鹿じゃねえのかと。
結論としては、かなり「根深い」ところで「駄目」なので、この「駄目さ」は未来永劫変わらないだろうと予想できます。少なくとも当面、7.xいや8.xぐらいはまだまだ駄目でしょう。大幅な設計変更が必要です。もう「これはもうPHPじゃないね」と言われるぐらいの。

こんな駄目言語でも、仕事では使わざるを得ません。しかし、前述の通りの穴だらけ仕様なので、「安全」というか「バグりにくい」プログラムを書く方法はそんなに多くありません。
  • 関数の戻り値は
    • 常に同じデータ型で返す。しかも成功時のみ。
    • 失敗時は
      • やはりオブジェクト型で返す。例えばデータが見つからなければ 「「データが見つからない」を示すオブジェクト」をnewして返す。
        • 何故って、PHPが別の型に変換しやがった時に、迷宮入りする可能性が低いから
      • throw しまくる
        • データが見つからなければ、「データが見つかりません例外」を投げるべき。
        • 空の配列を返すとかだと、count()==0とかやらなければならなくなる。でもそれは空文字でもヒットするので、実はジワジワ危険だったりする。
          • is_array($result) && count($result)==0 とか馬鹿じゃねーのかと。
かなり駄目かつ、判りにくいですね。まあthrowする方が現実的でしょう。ただし例外を投げても、catchしてもみ消す人もかなり多いので元の木阿弥だったりします。

2011年8月28日日曜日

PHP 5.4、一体どこへ向かってるのか?

筆者は何度となく、
  • 「mix-inは必要」
  • 「そのための多重継承は必要(悪)」
論じておりますが、PHPも5.4に至ってようやくmix-in専用機能がついたらしい。

サンプルソースはここから拝借。
http://simas.posterous.com/new-to-php-54-traits

trait Singleton {
public static function getInstance() { ... }
}
class A {
use Singleton;
// ...}
class B extends ArrayObject {
use Singleton;
// ...}
// Singleton method is now available for both classesA::getInstance();
trait??トレイト???辞書を引くと「特徴」という意味らしい。

うーん。また気持ち悪い英単語を持ってきましたね。苦肉の策って感じです。

PHPの機能拡張に置ける伝統的なセンスとして
  • 配列でなんとかする。call_user_funcでのオブジェクトメソッド呼び出しとか。
  • 文字列で渡す。クロージャっぽい事をやるときとか。
  • 予約語を1個づつ増やす。今回のコレ。
という印象をもっており、またしてもtraitとuseを増やしてきました。予約語を増やすにしても、単語1個づつでどうにかしたい感がしますね。

例えば、こうは出来なかったのか?(1)
mixin class A {}
class B {
  mixin use A;
}

理想をいえば、こうですね。(2)
class B extends A uses XC,XD implements IE,IF {}

「定義の内側に、何かを加えて何とかする」感はperlのOOPを思い出します。ただしperlは、サードパーティライブラリなので、本体を改造できないのはともかく、開発元のはずのZendがやるってのに、こんな手抜き感実装ってどうなの?

2011年8月23日火曜日

「動的言語で安全なソフトは作れないのか」

まあ、ぶっちゃけ、どの言語を使おうが、バグは出ますよね。

動的言語の代表と言えばPHPでしょう。残念ながらね。
しかしこれはバグの出やすい言語の代表格である。
暗黙のキャストが邪悪だったり、
であるにも関わらず0とFALSEを混同する組み込み関数が多数だったり。

一方、静的言語の代表格といえばJavaでしょう。これも残念ながら。
筆者の解釈では、「言語仕様側から、バグを減らす努力をした言語」。
public classを使うときは、ファイル1個に1クラスしか書けないとか、
機械的にチェックが可能な事柄で、ガチガチに締め上げた。
しかし、それこそがEclipseの様な優れたIDEを必須にしてしまった。
面倒臭すぎる。人力でリファクタリングとかあり得ません。

ただし、それでバグが減ってるかというと、それはやはり製作者依存なのです。
メソッドにHashMapを入れてたら、知らない間にパラメタを捻じ込まれてて、
忘れた頃に、別のメソッドでそのパラメタを使ってるとか。
乱暴な奴は、何の言語を使おうが、乱暴なことをやります。
#HashMapを使ったのが悪い。というツッコミは間に合ってます。
#静的言語で、動的考え方をしてるのが間違ってる。とも言える。かな。

一般論としてはどうなのだろうと検索してみたら、酷いスレ発見。

やっぱり動的言語では安全なソフトは作れない 3
http://logsoku.com/thread/hibari.2ch.net/tech/1308499587/

基本的には高尚な議論なんだけど、uy氏の逆ギレっぷりが見苦しい。
頭は良さそうなんだけど、自分より相手が下だと見るに一転挑発モード。
なんだろうなこういうの。

本題に対しての、筆者の個人的にな意見は、最初の1行目に尽きますが。

YESであり、NOである。とも言えるでしょう。

型チェックをやろうがやるまいが、それを通り抜けるバグは必ずあります。
テストが減る。というのには反論しませんが、要らなくなる訳じゃない。

そういう考え方でいえば、関数型の定義が究極なんだろうか。
あの界隈よく判りません。

ですので、「何を使っても、安全なプログラムはあり得ない」ということになる。
なにしろ、作ってるのが人間ですから。
コンピュータは人間が間違えた通りに間違えるだけ。
それがNO。

故に、「間違えない様に作ろう」=「安全に作ろう」というのは自然な流れでしょう。

努力次第でYESに近づけることは出来るでしょう。

本論は、基本的には、プログラム内部を通り抜けるデータの話に終始してますが、大規模プログラミングには、名前空間があればどうにでもなると思っています。具体的にはJavaにもC++にも有りますよね。静的言語の代表格です。#ようやくPHPにも入りましたが。バックスラッシュって何なのよ。

2010年12月5日日曜日

PHPの本当にあった怖い話(1)

筆者はPHPを仕事で使うようになって5年経ちますが、それは自慢になりません。
何故なら、未だに裏切られます。

結論から言いましょう。


$aaa = range("0","9");
$bbb = range("a","z");
$ccc = array_merge( $aaa, $bbb );
$ddd = array_search( "a", $ccc );


この$dddには何が入るのか?10が入って欲しいですよね?
0です。

この理由がいきなり説明できる人は、PHPの仙人もしくは関係者でしょう。
師匠もしくは、インサイダーと呼ばせてください。

実は最初のrangeが曲者です。
これは"0"と"9"を指定したにも関わらず、intの配列を作ります。
結果、$cccの中身にはintとstringが混在していることになります。

まだ前フリです。

そしてarray_searchで何が起こるのか?

"a"を探せ、って言ってるのに、intval("a")==0 で0番目が一致しちゃってるのです。

ありえなくね?

結論として、前述の例では、rangeとarray_searchの挙動の共犯です。

PHPは、こういった「暗黙の型変換」が大量にあり、warningすら出ません。
http://www.php.net/manual/en/types.comparisons.php

sortについては、これを反映して、「比較「型」の強制」があります。
http://www.php.net/manual/en/function.sort.php

しかし、array_searchには無いわけです。

初心者のうちは助けられることが多いと思いますし、
それを意図しての型変換でしょう。
しかし、中級になったとたん裏切られるのです。

これを期待通りに可動させるには、rangeの結果にstrvalを通す必要があります。


$aaa = array_map( "strval", range("0","9") );
$bbb = range("a","z");
$ccc = array_merge( $aaa, $bbb );
$ddd = array_search( "a", $ccc );


ありえなくね?

2010年9月12日日曜日

PHP5.3の名前空間がイケてない

名前空間の実装は、コンパイラ実装者にとっては悩みの種でしょう。
そういう事にしてください。

散々悩んで、PHP5.3みたいな有様になってしまうケースもままあります。

pythonの厳密には「モジュール」があり、その内側で「名前空間」に近い概念が使えますが、
非常に洗練していて、矛盾がありません。
その根幹は、名前空間ですら「オブジェクト」であるからです。
具体的には、module型。らしい。

  • Pythonのmodule型では
    • 1ファイル中で、名前空間(的なもの)を切り替えることは出来ない。
    • 変数や関数群は、単に実行中のmoduleのプロパティの一つに過ぎない。
    • importは、module型オブジェクトを、同名の変数に取り込む。
    • クラス定義(オブジェクト)とインスタンスは、収録している変数が違う筈なので、混同のしようがない。

javascriptも、これに近い運用ができますね。
端的に言えば、「別の名前をつける筈」なので、「「名前空間名と、クラス静的メソッド等を混同する」ような作り方はしない」

故に、これが、「名前空間専用の、階層区切り文字の設置」の理由にはなりません。
こんな理由が、バックスラッシュの理由で、まかり通っちゃ如何でしょう。
PHP関係者が、如何に他の言語畑とくらべて緩いのか。
言語側から、これを強制できなかったのは、PHP5.3の大失敗の一つでしょう。

PHPの名前空間の区切りがバックスラッシュになったのはそんな理由だったのか

誰かさんの記事ですから、また聞きですが

http://blog.ohgaki.net/php_5_3_namespace

何故このようなエントリを書くかというと、Software Design(技術評論社)の11月号にPHPの最新情報としてα版PHP 5.3を紹介しているからです。入稿後に仕様変更があったので最新号の記事ですが既に内容が古くなってしまいました。
# とは言ってもまだ新しい仕様のPHPは無いですが
α版なので仕様や機能が大きく変更される事もありますが大きな変更がありました。見本誌が刷り上がった頃に名前空間の区切り文字が"::"だと静的にメソッドを呼び出す場合やクラス定数を呼び出す場合に困る場合がある、とPHP開発者のMLで議論になり始めました

マジで?
イヤイヤ、その反論はオカシイデショウ。(リンク先の方に反論している訳ではありません)
という反論は誰かがしているはずだと思いたい。

よく読んでないけど、さらにそれの反論が、これかな。英語なんだよなー。

http://www.sitepoint.com/blogs/2009/08/13/are-php-namespaces-bad/

「静的メソッド&静的クラス変数を呼び出す時に困る。」
そうならないための名前空間じゃないのかと。

もしくは、作り方が下手なんじゃね?
もしくは、「困る」なら、その人にとっては要らない機能なんじゃね?

名前空間とクラスが、どうやら完全に別物だと考えちゃってるのだけど。
pythonを経験すると、決してそうではないということが解る。

やはりそもそもの失敗が、変数と、定数とで、それぞれ構文が違っちゃってるところ。
(まさかその時にも、「○○の時に困る」とか誰か反論したんじゃないでしょうね?!)
コンパイラが継ぎはぎだらけなのは明白です。
さらにそれに、名前空間のために、新しい「継ぎはぎ」を加えたのでしょう。

2010年9月4日土曜日

hiphop for PHPで頑張れない

出稼ぎ先の事情で、hiphopを試そうとしました。
facebook御謹製の、php/C++トランスレータです。
http://github.com/facebook/hiphop-php

結論から言うと、トランスレートまでは何とかテストできたのですが、
それのコンパイルで挫折しました。

  • まずは、facebookとしてはcentosを推奨しており、筆者の環境(ubuntu lucid(10.04))で動かすには意外と骨が折れたこと。cmakeとやらが全然通らず、仕方がないのでCMakefile.txtを修正したりとか。
  • 64ビットlinux専用。この為に、64bit ubuntuに入れ直した。
  • PHPのinclude_pathを参照しないので、フレームワーク群を多用しているソースは、正常に変換できないこと。
  • コンパイル時点で解決できない外部includeは、一応はincludeのままで残るが、挙動としてはhtmlの表示しか使えなさそう。
  • 「変換」したcppソースのbuildには、hiphop自身のincludeファイル群を必要とすること。
  • クラス群の「変換」では、クラス変数やクラス関数群に全てユニークIDを振っており、どうやらそれは「変換」したソースにも現れる。
  • クラスメソッド呼び出しは、クラスの問い合わせ関数に、メソッド名を指定している。何もかもcall_user_funcを使う感じ。オーバーヘッドが凄そう。


総合して、hiphopに向いた書き方が必要で、赤の他人が別のプロジェクトに適用するにはまだ辛いかなと。

特に、ユニークIDと問い合わせ関数はどうかなと思った。これは変換とは言えない。「展開」ですね。

native C++に変換しながらも、PHPより2倍、としか言えてないところも、
オーバーヘッドが大きいことに起因しそうです。

これだったら、最速と名高いlua(http://www.lua.org/)に「展開」する方が現実的か?とも思ったりします。

2010年8月19日木曜日

PHPが目指すもの

ここ最近、付け焼き刃的アンチPHP振りが恥ずかしくなってきたので、
今一度初心に帰って、PHPの目指すものを考察してみたいと思います。

筆者は、web業界としては古株で、それこそ「perlでCGI掲示板」からやってます。
pythonは既に存在していた筈ですが、日本ではまったく無名でしたね。

perlの頃は

実装については、CGI非専用言語なので、HTTPレスポンスヘッダを
自分で吐かなければなりません。これは初心者にはちょっと辛いかも。

また、レスポンスヘッダを作成するまえにエラーで落ちたりすると、
エラーメッセージがブラウザまで返って来ません。
これもデバッグが面倒でした。suexecやってたりすると更に面倒。

更にperlで中規模以上の開発をやろうとすると、問題になるのがCPAN。
CPAN自身が問題というよりは、大体稼働場所が「レンタルサーバ」なので、
新しいCPANは入れさせてもらえない。という事に成りがちです。

そこから行けば、PHPは天国です。

スクリプトでエラーが出ても、画面にペロっとメッセージが出てくれます。
厳密には、その設定はデフォルトoffだったりするのですが。

application/x-urlencodeの場合、ブラウザから送ってきた筈のデータは
既に「$_REQUESTに入ってる」。これは単純に、楽ちんです。

何処のレンタルサーバでも、概ね「全部入り」なので、
開発環境と稼働環境の統一に、あまり悩まなくて済みます。

また言語自体は、プラットフォーム依存は、あまり有りません。
#厳密には、アーキテクチャ依存はあったりしますが。

「サーバはWindows 20XX Serverです」とか言われると、ぶっちゃけ血の気が引きますが、
apache2とphpをインストールするだけで、
動いてくれるのは、軽量言語としては貴重です。

#サーバが、IISで、ActivePerlを入れて。とか。考えたくない。


忘れがちなのが、セッション処理を内蔵していること。筆者はperlでクッキーセッションを自力実装して、バグった事があります。クッキーを受け取らないブラウザでは、複数の人間が同じデータを参照してしまうというバグ。サービスサイトでは恐ろしい限りです。


総評として、

「perlより、そこそこ楽にweb開発をする言語」としては、優秀である。

とは言えましょう。

しかし、「その他」が駄目だった。

名前空間が有りません。
#perlには有ったのに。何で取っちゃったのか?

無いだけならまだよいのだが、前述の「全部入り」だと、
それだけ名前空間を食いつぶされるということでもあります。

array_*とか、ダサい関数名なら幾ら使ってもらっても構いませんが、
http://jp2.php.net/manual/ja/book.array.php
DirectoryIteratorとか、付けたくなるクラス名ですよね。
http://jp2.php.net/manual/ja/class.directoryiterator.php
#実際、php4から5の時に、それで動かなくなったスクリプトが有ります。

5.3で、ようやく名前空間を実装しましたが、
名前空間の区切り記号がバックスラッシュです。
http://jp.php.net/manual/ja/language.namespaces.nested.php
「サブ名前空間」?
名前空間に「サブ」ってどういうこと?
これ正直、気持ち悪いのですが。

#と思ったら、意外と受け入れられてるらしく、
http://blog.asial.co.jp/658

組み込み関数で、戻り値に整数型と論理型が混在してます。
混在するだけならまだ良いのですが、統一性がありません。
http://jp2.php.net/strpos
http://jp2.php.net/manual/ja/function.preg-match.php
falseの使い方に注目。

本質的な問題として、
バージョンアップで何かしら言語を拡張しようというときに、
「組み込みクラスを増やす」「組み込み関数を増やす」。それはまだいいのですが。
その他は「連想配列でなんとかする」という凄いポリシーを感じます。

この辺りの象徴は、call_user_funcに或る。と言えるでしょう。
http://jp2.php.net/manual/ja/function.call-user-func.php
1番めの引数には、「関数名」を「文字列」で渡します。

これだけでも気持ち悪いのですが、じゃあオブジェクトの場合はどうするのか?
array($classname, $methodname) これを入れろと言ってます。
前者は概ね、& $thisと書くべきでしょう。

$return = call_user_func( array( & $this, "method1" ), $param1 )

ナニコレ。気持ち悪いこの上なし。

総論に追加しなければなりません

しかし、中規模以上の開発に使うには難あり

理由は主に前述の通りですが、

一番の理由が名前空間が無いので、人間が「名前空間エミュレーションしている」。

ディレクトリ名はクラス名に前置するのが流行ってます。
Zend_Db_Table_Abstractとか。しかしこんなのは、完全に対処療法です。

必然、プロジェクトファイル群の構成として
長いクラス名と、
深いディレクトリ構造に、
大量の細かいファイル群を扱わなければなりません。

人間が手動で扱うのには無理があります。

統合環境を使わなければやってられません。

「お気楽言語であった筈」のPHPに、
「Javaの面倒くささ」を持ち込まざるを得なくなってしまったという。
本末転倒と言うか、ミイラ取りがミイラになるというか?
アレJavaがミイラ?

強調しておきますが、筆者は、統合環境にもJavaにも好意的ではあります。
Javaは「中規模未満の開発に使うには難あり」だと思ってますけどね。

2010年3月30日火曜日

仕事で使いたくないプログラム言語

結論から書きます。続編あり升

仕事で(プロが)使うなら、次のことをサポートすべき。
言い換えると、私が使うならサポートして欲しい。

  • 概ねオブジェクト指向 → 大規模開発に必要
  • 多重継承 → コピペ禁止。mix-inには必須。
  • 豊富なシンタックスシュガー → 細かい事なんか気にしてられない
  • 名前空間 → 大規模開発に必要
  • 豊富な標準ライブラリ。もちろん名前空間で適切に隔離していること。
  • 例外処理 → 大規模開発に必要
細かい話は、別エントリを書く予定なので、とりあえず割愛します。

日本では何やら、エンタープライズ界隈を中心に、
Java信仰なるものがあるっぽいですが、
Javaは小規模の仕事にはまるで向いてません。
10人月以上の案件に使うべき。
シンタックスシュガーが無いのもダメです。

今大流行りPHP系も、正直気は進みません。
重要な、名前空間と多重継承が使えません。
別エントリでも書いてますが、暗黙型変換が暴発してるので、
故に、今度は大規模開発には向いてません。
豊富すぎる標準関数が、名前空間を食いつぶすのもダメです。
PHPタグで始めなきゃいけない点も萎えます。

C++/C系は、生ポインタがある時点で、正直勘弁です。
言語は道具でしかありません。
受注金額がゴリゴリ落ちてるこのご時世、
メモリ確保と開放の心配までやってられません。
人間のやることですから、メモリ開放なんて、忘れるに決まってます。

Perlは、「CGI言語」として定着しましたが、
最近はPHPにその人気を奪われがちです。
オブジェクト指向の切り口が特異なのと、例外処理が無い点で、
仕事言語としてはマイナスです。
Mooseとやらのお陰で劇的に改善しては居るらしいですが。
いや、嫌いじゃないですけど。括弧を省略できたりとかね。
わざわざ「Perlで書いてね」なんて酔狂な顧客は居ないでしょう。

2010年3月22日月曜日

PHPって何が駄目って on PHP 5.2.X

5年ばかり、PHPで仕事をしてました。してたときは気にしてなかったというか、なんとなく引っかかってたんですが、pythonと比べると、駄目さが解ります。

一つは、名前空間がないこと。

PHP4で書いたスクリプトが、PHP5で動かないというのはままあります。
構文的な違いもさることながら、組み込み関数/クラスをドカドカ増やす。

私がPHP4時代に仕事で書いたスクリプト。
ディレクトリ検索クラスにDirectoryIteratorと付けました。
付けたくなる名前ですよね。ハイもう落ちが解りましたね。

PHP5になったら、定義済みクラスなので、2重定義でピクリとも動かない。
定義済みクラスってなに?includeしてないよ俺?度肝を抜かれました。
こっちが避けるしかないので、DirectoryIterator1とかに改名。

豊富な組み込み関数&クラスがPHPのウリなのかも知れませんが、
いらない人も居るんだよ、って話が抜けてる。
DirectoryIteratorはSPLエクステンションだが、PHP5.3で内蔵にしちゃったらしい。
http://www.php.net/manual/ja/spl.installation.php

大きなお世話です。

PHP5.3で名前空間をようやく実装したらしいですが、
「名前空間専用の区切り文字」が有って、バックスラッシュでした。
http://www.php.net/manual/ja/language.namespaces.nested.php

正直気持ち悪いんですけど。そうせざるを得なかった理由は想像できる。

オブジェクト指向の実装が不完全なので、階層管理が出来なかった。
なので、識別子名レベルでの代替手段を使った。
ピリオドもコロンも使用済みなので、バックスラッシュしか余ってませんでした。
変な文字も使えるようにして、名前空間っぽく使ってね、みたいな。
のかな?

もう一つは、暗黙の型変換の脅威。

PHPは、知らない間に、過激な型変換をしていて、それで知らずにバグることがあります。
例えば、これが通ります。
"" == 0 
あえて型変換を強調して書いてみましょう。
(int)"" == 0 
意味解らないでしょう?
もちろん、わざわざこんなif条件を書くのは変態です。
しかし左辺が変数だったら
$result == 0
よくある話でしょう?

こういう実装になってる事情は解ります。
多分彼らはコレをやりたいのでしょう。
(int)"9" + 3 == 12 
PHPは、左辺を優先して、型変換を繰り返している。
確かにwebベースのプログラミングで、数値変換はよくある話。
手間が省けるのは歓迎です。

入力値に対しては良いです。

これがハマりそうなケースは、関数の戻り値。

PHPの組み込み関数でも、intとfalseを使い分けちゃってるケースが結構あります。
例えば、mb_strpos。見つかると文字の位置を返しますが、見つからないとfalse。
先頭に引っかかった場合は0を返しますが、== falseとかでチェックしてると通りません。

PHP4で書いて、PHP5で動かなくなる話にも、これが関わってきます。
組み込み関数の挙動が微妙に変わってたりする。
エラーの時は、-1を返す、と思ってたらfalseを貰った、とか。
エラーを < 0 で判断してたら、正常で通過しちゃうわけです。

大昔に書いたプログラムを改造する場合にも、この辺りで微妙にバグる可能性もあります。

これは正直、センスを疑いますが、事情は想像できなくもない。
PHP4時代には例外は無いので、戻り値で遣り繰りした。
しかし、式実装全体としては、intとboolが区別できてる癖に、
暗黙の型変換をしちゃうという、チグハグな実装。
かな?

総評として、「安全に」「大規模な」プログラムを書くには、無理がありそう、
と言えます。