Home > PHP
PHP Archive
フレームワークで使われているPHP関数を数えてみた
CakePHPを使ってからempty()を使うようになった、なんて話が以前社内でもあったので、各フレームワークで使われているPHP関数を調べてみました*1。
調べたのはCakePHP/symfony/ZendFrameworkで、それぞれ最新版を使用しています。
あと関数全てを載せると長いので上位20件のみ記載しています。
CakePHP-1.2RC1
array()が圧倒的ですね。2位以下もin_array()から5位のis_array()まではarrayに関係する関数となってます。
さらにarray()自体の数がスゴイです。ソースコードは3つの中で一番少ないのですが(symfonyの約2/3、ZFの約1/3)ですが、array()はsymfonyの約5倍、ZFの約2倍となっています。
いかにCakeがarrayを多用しているかが、良く分かります。
ソース行数:126,469行
16645 array 1519 in_array 1151 isset 889 empty 486 is_array 454 str_replace 378 unset 314 strpos 302 array_merge 270 count 241 sprintf 235 preg_quote 169 define 165 date 148 file_exists 148 preg_match 146 strtolower 144 explode 134 extract 134 substr
symfony-1.1.0RC2
やはりarray()が一位ですね。Cakeと違うのところでは、sprintf()が3位に来ています。さらに4位にsubstr()、5位にstrlen()と文字列関数が上位に来ています。
ソース行数:179,517行
3534 array 1083 isset 729 sprintf 515 count 372 substr 256 strlen 230 is_null 229 is_array 218 dirname 213 empty 204 strpos 201 unset 198 array_merge 164 in_array 156 str_replace 155 strtolower 150 preg_match 134 date 133 implode 124 preg_replace
ZendFramework-1.5.1
ソースコード行数が最も長いZFです。これもやはりarray()が1位となっています。4位にdirname()が入っています。Cakeでは50位(53件)、symfonyで218件(9位)なので、多いように感じます。あとord()が8位に、definedが12位などが上2つとは違う点でしょう。
ord()でソースをgrepしてみるとPDFやLucene、NTP関連のソースが引っかかりました。このへんはライブラリ的要素が強いZFの特徴ですね。
ソース行数:372,103行
8686 array 1528 isset 1407 count 999 dirname 789 is_array 650 empty 542 unset 508 ord 334 strlen 326 substr 295 array_key_exists 286 defined 243 explode 233 is_string 215 strpos 205 preg_match 202 date 201 strtolower 189 define 180 list
DB関数に着目
DB関連の処理は3フレームワーク共にフレームワーク自体に機能があるので、通常はPHPのDB関数を直接実行する必要はありません。これはフレームワーク内の処理も同様で、SQLを直接発行する箇所は1つにまとめておいて、各箇所からはそこを呼び出すイメージです。
よってpg_queryやmysql_queryは1つしか登場しないと思っていました。
Cakeは想像どおりそれぞれ1つしかありませんでした。ZFもPDOを使用しているのでこれらの関数自体が無いのですが、Oracleのoci_executeは2つ(1つはテスト)のみでした。
さて残るsymfonyですが、なぜかmysql_queryが27、pg_queyが20となっていました。あちこちに書いているのには、何か理由があるのでしょうか(歴史的な理由?)。
最後に関数の種類
最後に関数の種類ですが、3フレームワーク共に400前後でした。
もう少しじっくり見ると面白いところがあるかもしれませんが、今回はこのあたりで。
*1 array()やempty()など厳密には関数でないもののありますが、ここでは本質では無いのでスルーしてください;-)
- コメント (Close): 0
- Trackbacks: 1
PHP 意図を伝えるコーディング
- 2008-06-11 (水)
- PHP
PHPに限らずですが、読む人に意図が伝わるようなコードを書きたいという話です。
なお以下は私の感覚での話しですので、それ違う!という突っ込みがあればお願いします:-D
業務にしろオープンソースにしろ人のソースを見て気になるのがif文です。
if文で真偽値を判定する
メソッド・関数の戻り値が真偽値の場合、true/falseを判定するなら等号(不等号)は無くても良いのではないでしょうか。
つまり(hoge()はtrue/falseを返す関数)
[1]
if (hoge() === true) { } if (hoge() !== true) { }
と書くのではなく
[2]
<?php if (hoge()) { } if (!hoge()) { } [/php] <p>と書けば良いのでは、という事です。</p> <p>特にPHPでは厳密にtrue/falseを判別するなら[===]で比較する<a href="#1" name="p1">*1</a>ということで、[1]のようなコードを見るのですが、ここで判別したいのは、true/falseの2値のみなので、型を厳密に見る必要はありません。</p> <p>[2]であればhoge()が2値のみを返す(他の値を返すにしても2値のどちらにみなされるか、だけを判定している)意図が明確になります。</p> <p>私の感覚では[1]のように書くとhoge()がtrue/false以外の値(integer等)を返すので、あえて[===]で判別しているようにも取れます。</p> <p>コードの解釈できる範囲を狭めてやることにより、コードの意図がはっきりします。</p> <p></p> <p>PHP5で強化されたオブジェクト指向機能を使うことにより、コードの意図を伝えることができます。</p> <h3>例外</h3> <p>try/catchで例外を捕捉しているコードなら、その中で例外が飛んでくることが分かります。さらにcatchで捕捉する例外を絞り込めば、飛んでくる例外の種類も分かります。</p> <?php try { // foo()内でPDOExceptionが発生する foo(); } catch (PDOException $e) { echo $e; } [/php] <h3>アクセス権(visibility)</h3> <p>インスタンス変数にprotected/privateを設定しておけば、その変数が外部からは参照・変更して貰いたくないことが分かります。メソッドについても同様です。</p> <h3>タイプヒンティング(TypeHinting)</h3> <p>関数・メソッドの引数にタイプヒンティングでクラス(インターフェイス)名を指定しておけば、与えるべき引数が明らかになります。さらにPHPではタイプヒンティングで指定した引数へはnullも指定できない<a title="引数のデフォルトパラメータにnullを指定すれば、nullも渡すことができます。" href="#2" name="p2">*2</a>ので、メソッド内部では確実に指定したクラスとして扱えます。</p> <?php class Foo {} class Bar { public function execute(Foo $foo) { } } $bar = new Bar(); $bar->execute(new Foo()); // Fooクラスのインスタンスのみ
クラスを継承/インターフェイスを実装
当たり前に使っている機能ですが、これを行えば親クラスやインターフェイスで定義されているメソッドならば(publicなら)呼べることが分かります。またそのクラスがどんな責務を負っているか、何に使うべきかを知ることができます。
意図を伝えられるコーディングを
例をいくつか書いてますが、大事なのはコードを読む人(一ヶ月後の自分も含む!)に意図を伝えられるコードを書きたい、書こうということです。
# コメントも大事ですが、実際に動くのはコードなので、まずコードがあってこそですからね。
追記[2008/06/12]:
if文の話には別の視点があるようです。人間って疲れる生き物なのですよ – よくきたはてダ
*1 PHPの==がキモい件 – hnwの日記
*2 引数のデフォルトパラメータにnullを指定すれば、nullも渡すことができます。
- コメント (Close): 0
- Trackbacks: 0
CakePHP 1.2RC1からは比較演算子をキーに書く
- 2008-06-10 (火)
- CakePHP
via: “1.2RC1でのSQLインジェクション対策” フォーラム – CakePHP Users in Japan
リンク先にあるとおり、1.2RC1ではfind()の条件を指定する際、比較演算子を配列のキー側に書くように変更されています。
CakePHPでは値の先頭にある比較演算子をSQLとして実行してしまう特性があったので、1.2betaまでは以下のようなコードを記述していました。
// $id = 1が外部から来るとする $user = $this->User->find(array('id' => '= ' . $id));
しかし1.2RC1でこのコードを実行すると[‘= ‘ . $id]が値として認識されてしまいます。
SELECT * FROM users WHERE id = '''= '' 1';
1.2RC1では条件配列のキーの部分に比較演算子を書くようになっています。
// 比較演算子の前に半角スペース[0x20]を入れる $user = $this->User->find(array('id =' => $id));
キーに演算子が無ければ[=]とみなされるので、等号で比較するなら[‘ =’]は省略できます。
$user = $this->User->find(array('id' => $id));
LIKE句なども同様に配列キーに記述します。
$list = $this->User->find('all', array('conditions' => array('name LIKE' => '%foo%')));
通常、条件配列のキーはコードに直接記述するため、外部からは変更できません。セキュリティを高める意味でこれは良い変更だと思います。
# これでいちいち[‘= ‘ . $value]と書くのから解放されます。:-D
ただ1.2betaまでに合わせて書いたシステムでは、1.2RC1へ移行する際は修正が必要になります。
- コメント (Close): 1
- Trackbacks: 1
PHP NULLかどうかはis_null()を使う
- 2008-06-07 (土)
- PHP
同い年(学年は違うけど)なhnwさんの[==]なエントリです。
# この話はPHPを使う上では大事なことなので、知らない方はリンク先を確認してください。
型まで厳密に見るときは[===]を使う必要があるのはエントリのとおりなのですが、NULLかどうかを調べるにはis_null()を使う方法もあります。
SQLのIS NULLと同じノリですね。
[==]と[===]を使い分けずとも、明示的にNULLを判別しているのが分かるので良いかと。
- コメント (Close): 0
- Trackbacks: 0
CakePHP PostgreSQLではgetInsertID()に注意
- 2008-06-07 (土)
- CakePHP
@deprecated
この情報はCakePHP1.2RC1までのものです。2008/06/26現在のリポジトリではチケットが反映され修正が完了しています。
CakePHP+PostgreSQLでModel#getInsertID()を使う場合、別セッションのシーケンス値が取得される問題があります。
問題点
ユーザ情報とその付加情報や、注文情報と明細情報などINSERT後にそのレコードに関連する情報としてid値を活用する場合、本来とは異なるレコードに結びつく可能性があります。
ex) 別の注文情報に明細が登録される等
ただ、これはほぼ同時にINSERT文が発行された際に起こる現象ですので、それほど登録処理が行われないサイトではあまり遭遇するものではありません。(ですので、これまであまり表面化しなかったかと。)
CakePHP1.2RC1/1.2-beta/1.1.19でこの問題があります。
解決策
フレームワークを修正して貰えるようにチケットは投げています。
https://trac.cakephp.org/ticket/4832
現状のソースのままで対応するなら、INSERT前にLOCK TABLEで該当テーブルをロックしておくことで対応できます。(nextval()で直にシーケンス値を変えられるとNGですが。)
<?php // Order は Model $this->Order->begin(); $this->Order->query('LOCK TABLE orders IN EXCLUSIVE MODE'); if (!$this->Order->save($data)) { $this->Order->rollback(); } else { $this->Order->commit(); } ?>
概要
PostgreSQLでは、自分が発行したINSERT文に対するシーケンス値を取得する際はcurrval()というPostgreSQLの関数を使用します。この関数は自セッションで発行された最新のシーケンス値が返ってくるので、別セッションでINSERT文が発行されても値は変わりません。これにより自分がINSERT文で追加したレコードを特定できるわけです。
SELECT currval('hoge_id_seq');
以前はCakeでもこのcurrval()を使って実装されていたわけですが、いつの頃か実装が変わって、現在のlast_valueを取得する形に変わっています。
SELECT last_value FROM hoge_id_seq;
last_valueはシーケン自体の最新の値になるので、上記のように別セッションにてINSERT文が実行されると、そちらで割り当てられたシーケン値が返ってきます。
流れとしては下のようになります。(初期シーケンス値が0、A/Bが同時に登録したと仮定)
[SQL]
CREATE TABLE hoge(
id serial primary key
,name text
);
[/SQL]
[SQL]
A: INSERT INTO hoge(name) value(‘foo’); // id=1
B: INSERT INTO hoge(name) value(‘bar’); // id=2
A: SELECT last_value FROM hoge_id_seq; // 2!
B: SELECT last_value FROM hoge_id_seq; // 2
[/SQL]
この場合、どちらも2がModel#getInsertID()の値として返ってきます。
当然この値をhoge_idとして別のテーブルに登録すれば、本来hoge_id=1に登録されるべきであったレコードがhoge_id=2として登録されてしまうわけです。
頻度は少ないが、発生すると問題
それほど発生することは無いにせよ、発生した際の影響が大きいです。(注文情報とカード番号が別テーブルになっていて、別の注文情報にカード番号が登録されたら。。。)
フレームワークが修正されるのも大事ですが、LOCK TABLEを活用してトランザクション内で別のINSERTが発生しない(シーケンスが進まない)方がより安全に登録処理を行うことができます。状況が許すなら活用してみて下さい。
- コメント (Close): 2
- Trackbacks: 1
[告知] 第3回CakePHP勉強会が開催されます。
第3回CakePHP勉強会を開催します。
CakePHPの活用事例やさまざまなネタで交流し、さらに広がるCakePHP界を盛り上げましょう。
第3回CakePHP勉強会が6/27(金)で開催されます。
場所は前回と同じくトライコーンさん(いつもありがとうございます!)です。
今回もyandoさんの尽力のおかげで強力な事例発表があり、かなり楽しみな内容となっています。Cakeな方もそれでない方も是非ご参加下さい;-)
申込は6/3 13:00から↓のリンク先からお願いします。ここ最近PHP関連の勉強会は申込開始から数十分(!)で定員が埋まってしまうこともあるので、お忘れなく。
概要・申込は、第3回CakePHP勉強会 – events.php.gr.jpからどうぞ。
- コメント (Close): 0
- Trackbacks: 0
CakePHP 1.2beta対応-CakeInfo-0.1.2リリース
CakePHPアプリケーションの内容をphpinfo()風に見せるCakeInfoをCakePHP1.2-betaに対応しました。
主な変更点は以下です。
- CakePHP1.2-beta対応
- Controllerにaction_methodを追加
今回追加したControllerのaction_methodでは外部からアクションメソッドとして呼べるメソッドを表示しています。これを見ると公開するつもりの無いメソッドが公開されていないかを確認できるので、自作のCakeアプリにて試してみてください。
設置
設置方法は簡単です。
まず[http://www.1×1.jp/blog/download/cakeinfo-0.1.2.zip]からzipファイルをダウンロードします。
あとはダウンロードしたzipファイルを展開し、[cakeinfo.php][logo-mini.gif]を[app/webroot/]に設置するだけです。
設定
現在のところ設定項目は[DATABASE_CONFIG_FLAG]一つだけです。
- DATABASE_CONFIG_FLAG
この定数が設定されていればDatabase項目が表示されます。(デフォルトはコメントアウト)
自作のアプリ以外にも、オープンソースで公開されているシステムの解析(の取っかかり)にも使えますね。お試し下さいませ:-D
- コメント (Close): 1
- Trackbacks: 1
CakePHP パフォーマンスが出ない時は、例えばフレームワークを避ける
フレームワークを使ってパフォーマンスに問題があったため、Plain PHPで書き直したという話です。
先日受信したメールの内容を.forward経由でDBを保存するという処理を実装しました。まあ良くある処理なのですが、このシステムではWeb側をCakePHPで実装していたので、メール処理もCakePHPのCLI機能(cakeコマンド)を利用しました。
実際に動作してみて数件程度では問題無かったのですが、負荷試験として短時間に数百件、数千件のメールを受信させると、LAが80程度まで跳ね上がりました。処理自体を見直したり、不要なSQLをカットしたりしたのですが、それほど大きな効果はありませんでした。
これはフレームワークの起動に時間がかかっていると判断し、CakePHPを使わずベタなPHPスクリプトだけで実装してテストすると、同じ負荷をかけてもLAが3-4程度まで落ちました。
timeコマンドで実行時間を計測しても、3-4倍の差がありました。(もちろんPHPスクリプトだけの方が早い)
$ time hoge.php
実はこういった場面はこれまでも経験していて、Web側では負荷が高い箇所やパフォーマンスが出ない箇所ではフレームワークを使わずに実装することがありました。CakePHPにCLI対応が含まれているとはいえ、CLI環境においてもパフォーマンスが出ないシーンでは、あえてフレームワークを使わないという選択肢は覚えておく必要があります。
ただこういったケースがあるからといって、どんなケースでもフレームワークを全く使わないというのは賢明ではありません。
フレームワークで構築することには多くの利点があり、ある程度習得しているフレームワークであれば、PHPスクリプトだけで開発するよりも生産性や安定性等々で有利です。フレームワーク上で十分に性能が出ている場合はそのままで何ら問題ないです。
このあたりのバランスを保つのが大事なのですが、まずはフレームワークで構築しておいて、問題がある箇所を崩していくというアプローチが単純で良いかと。
今回の場合、フレームワーク上で実装していたものをPHPスクリプトで再実装したので、同じ機能をアプローチを実装しただけなので、短時間で再実装することができました。プロトタイプ的にフレームワークで組むというのも良いかもしれません。
CakePHPのDB設定を参照する
これに関連してミニTipsを。
フレームワーク無しで実装する際でもせめてDBの接続情報くらいは共有しておきたいものです。そこで今回はPHPスクリプトから[app/config/database.php]を参照するようにしました。
app/config/database.phpの情報からDBに接続する。
require_once('/path/to/cake/app/config/database.php'); public function connect() { $db = new DATABASE_CONFIG(); $dsn = sprintf("dbname=%s user=%s password=%s" , $db->default['database'], $db->default['login'], $db->default['password']); if ($db->default['host']) { $dsn .= sprintf("host=%s port=%d", $db->default['host'], $db->default['port']); } $this->conn = @pg_connect($dsn); if (!$this->conn) { $this->log(__FILE__ . ':' . __LINE__ . ' ' . $dsn); exit; } }
- コメント (Close): 2
- Trackbacks: 1
TwitterにいるPHPのすごい人リスト
ZEND DEVELOPER ZONEでPHPコミュニティのTwitterアカウントが紹介されています。
リストに並んでいるのはPHP本家の人や海外の人ばかりだったので、日本のすごいPHPerのTwitterアカウントを並べてみました。(()内はざっくりです;-))
TwitterをはじめたPHPerは要チェック!
- @LIND(baseball_flash、懇親会の人)
- @akiyan(はてぶTV、CakePHPの人)
- @bto(phshの人)
- @cocoitiban(Ethnaの人)
- @elf(よくきたなの人)
- @halt(Ethna、vimの人)
- @hiro_y(moonyの人)
- @hnw(round()の人)
- @ichii386(Ethnaの人)
- @iogi(PHP Extension勉強会の人)
- @iteman(Piece Frameworkの人)
- @junya(Sooey、guessworkの人)
- @kensuu(ミルフィールの人)
- @komagata(plnet.jpの人)
- @koyhoge(とにかくすごい人)
- @kumatch(Piece Frameworkの人)
- @kunit(Mapleの人)
- @masaki_fujimoto(PHP、Ethnaの人)
- @masugata(mbstringの人)
- @memokami(携帯の人)
- @moriyoshi(PHPの人)
- @mumumu(Ethnaの人)
- @nowelium(S2*.PHP5の人)
- @p4life(CakePHPの人)
- @rhaco(rhacoの人)
- @rsky(PHP Extensionの人)
- @shigepon(rhacoの人)
- @shimooka(Do you PHP?の人)
- @shin1x1(Twitter検索、CakePHPの人)
- @shoma(HTML_TagCloudの人)
- @sotarok(PHP Framework Fight! の人)
- @suzuki(メールの人)
- @takagi(phpdocの人)
- @tsukimiya(symfonyの人)
- @yando(CakePHPの人)
- @yohgaki(セキュリティ、PostgreSQLの人)
- @yonekawa(S2*.PHP5の人)
- @yudoufu(symfonyの人)
他にもTwitterアカウントが分からない人(この人とかこの人[@masugata?]とか)やリストに入っていない人、是非教えて下さい。:-D
追記(2008/05/04):@kensuuと僭越ながら@shin1x1を追加。
追記(2008/05/09):@mumumuと@masugataを追加。
- コメント (Close): 6
- Trackbacks: 4
Podcastで聞くPHP
- 2008-04-28 (月)
- PHP
先日ipod Touchを買いました*1。
買う前は、nanoやclassicとで迷っていた(特に価格面で)のですが、実際買ってみると独特のUIや液晶の大きさなど、とても気に入ってます。
iPodならPodcast、という事でPHPに関するPodcastを探してみました。
そこで見つけたのが、PHP Podcastsです。
PHPに関するPodcastと言えば、php|architect’s C7YやZendのPHP Abstractなどが有名ですが、PHP Podcastsはこれらのaggregatorとなっているので、ここをiTunesに購読しておけば、様々なPodcastをチェックすることができます。
PHP Podcastsでは以下のようなPodcastをアグリゲートしているようです。
- P3 (php|architect’s PHP Podcast)
- PHP Abstract
- The Show for CakePHP
- Drupal Podcast
- KILLER PHP
- Official phpBB Podcast
- WebDevRadio
- The WordPress Podcast
- The ZendCon Sessions Podcast
全て英語なのが寂しいところですが、本場の雰囲気を感じられて面白いです。(内容はちんぷんかんぷんですが:-P)
日本でも誰かやりませんか? > Podcast
- コメント (Close): 0
- Trackbacks: 0
ホーム > PHP
- 検索
- フィード
- メタ情報