Home > PHP

PHP Archive

Yahoo!でsymfonyを採用

  • 2006-10-29 (日)
  • PHP
この記事の所要時間: 28

Yahoo!の新サービスYahoo! Bookmarksはsymfonyで構築されているそうです。

But the real news about the new Yahoo! Bookmarks is that it was built with symfony. Why did Yahoo! choose our framework? According to Michael Salisbury, Technical Yahoo!, who was kind enough to give us his feedback, the major strengths of symfony over its competitors are:

* Great documentation
* Explicit and extensive configurability
* Active development
* Use of best-of-breed components rather than building everything again

The documentation was the first reason to choose symfony. It reaches a unique quality and coverage in the open-source world.

symfony PHP5 framework » Yahoo! bookmarks uses symfony (2006-10-29)

ドキュメントが充実していることが理由に挙がっています。フレームワーク(オープンソース)を広めるには機能や品質も大事ですが、やはりドキュメントの重要性は高いです。

このニュースはsymfonyを選ぶ良い材料になりますね。(PHPが広まる頃にも「Yahoo!が採用しているPHP」という言葉を見聞きしましたし、私も言ってました。:-))

CakePHPの前に少しsymfonyも触っていたのですが、両者を比べるとsymfonyの方がCakePHPよりも重厚なイメージがあります。CakePHPの軽快さ(良い意味で薄さ)が気に入っているのですが、中身が見えてくると「あれ?」と言った点が出てきたりしてます。もちろんこれを直せるのがオープンソースの良いところですけどね。;-)

CakePHPでも看板となるサイトを作っていきたいところです。

PHPのちょっとしたコツ

  • 2006-10-27 (金)
  • PHP
この記事の所要時間: 1115

ウノウラボ Unoh Labs: PHPのちょっとしたコツに興味深い内容が書かれています。

1. array_pushは遅い
いくつかのBlogで語られてることですが、array_pushは、次のような書き方のほうが早いそうです。

	//array_puth($array, \'arraydata\');
	$array[] = \'arraydata\';

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

これはほんとあちこちで言われていますね。実際にどの程度違うかベンチマークを取ってみました。

< ?php
require_once 'Benchmark/Timer.php';

$max = 10000;

$timer = new Benchmark_Timer();
$timer->start();

$array = array();
for ($i = 0 ; $i < $max ; $i++) {
  $array&#91;&#93; = $i;
}
$timer->setMarker('statement');

$array = array();
for ($i = 0 ; $i < $max ; $i++) {
  array_push($array, $i);
}
$timer->setMarker('array_push');

$timer->stop();
$timer->display();
?>

予想通りarray_pushの方が遅く、PHP4で約1.3倍、PHP5で1.6倍遅い結果になりました。

■PHP 4.4.4 (cli)
--------------------------------------------------------
statement   1161939536.23285200   0.012247085571289  43.97%
--------------------------------------------------------
array_push  1161939536.24843900   0.015587091445923  55.97%
--------------------------------------------------------
■PHP 5.1.6 (cli)
--------------------------------------------------------
statement   1161939530.12842400   0.0053808689117432  37.91%
--------------------------------------------------------
array_push  1161939530.13722100   0.0087971687316895  61.97%
--------------------------------------------------------

2. array_key_existsよりハッシュを使え
array_searchは、毎回全データを検索するので遅いです。
データに配列の順序が関係ないなら、連想配列 + issetを使うほうが高速です。

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

こちらもベンチマークを取ってみました。

< ?php
require_once 'Benchmark/Timer.php';

$max = 10000;
$array = array('abc' => 'abc', 'null' => null);

$timer = new Benchmark_Timer();
$timer->start();

for ($i = 0 ; $i < $max ; $i++) {
  isset($array&#91;'abc'&#93;);
  isset($array&#91;'null'&#93;);
  isset($array&#91;'none'&#93;);
}
$timer->setMarker('isset');

for ($i = 0 ; $i < $max ; $i++) {
  array_key_exists('abc', $array);
  array_key_exists('null', $array);
  array_key_exists('none', $array);
}
$timer->setMarker('array_key_exists');

$timer->stop();
$timer->display();
?>

やはりarray_key_existsの方が遅いです。こちらはarray_pushより速度差がの方が大きく、PHP4で約2倍、PHP5で約4倍(!)遅い結果になりました。

■PHP 4.4.4 (cli)
---------------------------------------------------------------
isset              1161938594.14881000   0.014264822006226  33.43%
---------------------------------------------------------------
array_key_exists   1161938594.17719700   0.028387069702148  66.53%
---------------------------------------------------------------
■PHP 5.1.6 (cli)
---------------------------------------------------------------
isset              1161938597.88852400   0.0043120384216309  19.44%
---------------------------------------------------------------
array_key_exists   1161938597.90638100   0.01785683631897  80.50%
--------------------------------------------------------

ただarray_key_existsとissetは全く同じ挙動を示すわけではなく、配列にキーが定義されているかを厳密に調べるにはarray_key_existsを使わざるを得ないようです。(@see PHPマニュアル-isset

4. if文は「===」を使う

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

これは趣味の問題かもしれませんが、odz buffer – PHPのイテレーションの話とかでodzさんが書かれている形が自然だと思います。特に

 if (is_null($null) === false) {

はis_null()がtrue or false以外の値を返すようで引っかかりました。(マニュアルを見直しました。:-))

5. countは配列数を毎回数えてる これを知ったのは、Pukiwkiのクリーンアップの記事を見たときなのですが。 countは配列の件数を数えるらしいので次のような書き方に直したほうが無難です。

ウノウラボ Unoh Labs: PHPのちょっとしたコツ

count()が実行毎に件数を数えるわけではないのはエントリで触れられているのですが、このtips自体が無意味なわけではありません。

count()の値をループ前に取得しておくのとループ内で呼ぶのとでベンチマークを取ってみると以下のようにやはり差が出ました。

※ソースはodzさんのを編集させていただきました。

< ?php
require_once 'Benchmark/Timer.php';

function test_count_loop($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        $n = 0;
        $count = count($array);
        for ($i = 0; $i < $count; $i++) {
            $n = $array&#91;$i&#93;;
        }
    }
}

function test_count_loop_count($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        $n = 0;
        for ($i = 0; $i < count($array); $i++) {
            $n = $array&#91;$i&#93;;
        }
    }
}

function test_foreach($array, $iterate) {
    for ($j = 0; $j < $iterate; $j++) {
        foreach ($array as $i) {
            $n = $i;
        }
    }
}

$a = range(0, 9999);
$b = range(0, 9999);
$c = range(0, 9999);

$timer = new Benchmark_Timer;

$timer->start();

test_count_loop($a, 1000);
$timer->setMarker('count_loop');

test_count_loop_count($b, 1000);
$timer->setMarker('count_loop_count');

test_foreach($c, 1000);
$timer->setMarker('test_foreach');

$timer->stop();
$timer->display();
?>
■PHP 4.4.4 (cli)
---------------------------------------------------------------
count_loop         1161943146.86602700   10.211816072464  34.91%
---------------------------------------------------------------
count_loop_count   1161943160.60222800   13.736200809479  46.95%
---------------------------------------------------------------
test_foreach       1161943165.90888800   5.3066601753235  18.14%
---------------------------------------------------------------
■PHP 5.1.6 (cli)
---------------------------------------------------------------
count_loop         1161943103.61103900   2.0879490375519  24.69%
---------------------------------------------------------------
count_loop_count   1161943108.41284200   4.80180311203   56.79%
---------------------------------------------------------------
test_foreach       1161943109.97873100   1.5658888816833  18.52%
---------------------------------------------------------------

以前はforよりforeachの方が速い遅いという話を聞いた事があったのですが、いつのまにかforeachの方が速くなってますね。普段は多少のオーバーヘッドは気にせずforeachを使っていたのですが、これで大手を振って使えます。;-)

CakePHP bake2タスクを作る

この記事の所要時間: 152

CakePHP bake2でテーブルひな形を作るでご紹介したように、1.2系に含まれているbake2では任意のタスクを呼びだせる設計になっています。なかなか面白い機能なので試しにHelloタスクを作ってみました。

bake2タスクはBakeTaskクラスを継承します。オーバーライドするメソッドはexecute()とhelp()メソッドです。名前のとおりexecute()メソッドではタスク処理、help()メソッドではタスクのヘルプを表示します。

[cake/script/tasks/hello_task.php]

< ?php
class HelloTask extends BakeTask {
    function execute($params) {
        foreach ($params as $param) {
            printf("Hello %s.\n", $param);
        }
    }

    function help() {
        echo "The Hello task \n";
        echo "Usage: bake2 hello name\n";
    }
}
?>

Helloタスクを呼びます。

FooとBarがHelloタスクへのパラメータになります。ソースを見ても分かるようにパラメータはexecute()メソッドに配列で渡されます。

$ php -f bake2.php hello Foo Bar
Hello Foo.
Hello Bar.

helpをパラメータにするとHelloタスクのhelp()メソッドが呼ばれ、ヘルプが表示されます。

$ php -f bake2.php hello help
The Hello task 
Usage: bake2 hello name 

 

単純ですがタスクを実行する仕組みが用意されたのは嬉しいです。コードジェネレータやDBのセットアップなど開発に役立つタスクを増やしていきたいですね。

CakePHP bake2でテーブルひな形を作る

この記事の所要時間: 114

テーブル生成・削除SQLを作成するタスクが紹介されています。

To make it a bit easier to write the sql scripts for creating and dropping tables, I wrote a simple bake task. There isn’t much to say about it, so I show you just an example.

cakebaker » A simple task to generate sql scripts (2006-10-26)

1.2系に付属されているbake2用のタスクです。

bake2.phpにテーブル名を指定すると、id(プライマリキー)・created(レコード生成日時)・modified(レコード更新日時)を持つテーブルの生成・削除SQLが[/app/config/sql]以下に生成されます。どのカラムもフレームワークで参照・更新されるカラムですのでひな形に含まれていると便利ですね。

ただ生成されるSQLがMySQL用なので他DBの場合はデータ型などを変更する必要があります。(生成対象のDBを[/app/config/database.php]を見て切り替えるという手もありです。)

bake2.phpを見ると任意のタスクを追加していけるようなので、こちらも色々と使えそうです。

PHPオブジェクトは配列より遅いか

  • 2006-10-17 (火)
  • PHP
この記事の所要時間: 352

以前のエントリでもあったようにPHPのオブジェクトは配列より遅いという印象があります。

実際にどの程度違いがあるかをPHP4/5で計ってみました。

計測方法

各ソースを100回実行した平均を出しています。実行環境はPHP4は4.4.4、PHP5は5.1.6(共にCLI版)です。実行時間の計測にはPEAR::Benchmark_Timerを使いました。

各ソースでは配列、Hogeクラス(オブジェクト変数なし)、Hoge2クラス(オブジェクト変数あり)を計測しています。なおHoge/Hoge2クラスは以下になります。

< ?php
class Hoge {
}

class Hoge2 {
  var $id;
  var $name;
}
?>

生成

配列・オブジェクトを1000回生成しています。[ソース]

PHP4

実行時間 比率
array 0.000901 1.000000
object 0.001261 1.399353
object2 0.001592 1.767612

PHP5

実行時間 比率
array 0.000334 1.000000
object 0.000721 2.156477
object2 0.000974 2.913505

やはり配列よりオブジェクトの方が遅いですね。オブジェクト同士でもオブジェクト変数を定義してある方が遅くなっています。

意外だったのがPHP4と5で速度比率の差が大きいことです。配列、オブジェクト共にPHP5の方が速いのですが、オブジェクトに比べて配列が圧倒的に速くなっているため速度差が大きくなっています。

書き

既に作成されている配列・オブジェクトに2つの値を1000回設定しています。[ソース]

PHP4

実行時間 比率
array 0.001422 1.000000
object 0.001336 0.939508
object2 0.001325 0.932387

PHP5

実行時間 比率
array 0.000593 1.000000
object 0.000761 1.283243
object2 0.000852 1.437950

「生成」ほどの速度差はありませんでしたが、PHP4では若干配列が遅く、PHP5ではオブジェクトが遅かったです。ここでもPHP5の方が速度差が大きいですね。PHP5ではobject2(オブジェクト変数あり)の方が遅いのはなぜなのでしょう。(オブジェクト変数が定義されている方が速いような気がするのですが)

読み

既に作成されている配列・オブジェクトの2つの値を1000回取得しています。[ソース]

PHP4

実行時間 比率
array 0.001971 1.000000
object 0.001867 0.947329
object2 0.001859 0.943242

PHP5

実行時間 比率
array 0.000710 1.000000
object 0.000771 1.086580
object2 0.000854 1.202299

「生成」「書き」に比べてほとんど差はありませんね。ただ「書き」と同じくPHP5のobject2は若干遅いです。

Recordset

DBから値を読むシーンを想定して、生成・書き・読みを1000回繰り返しています。[ソース]

PHP4

実行時間 比率
array 0.003775 1.000000
object 0.003988 1.056424
object2 0.004052 1.073377

PHP5

実行時間 比率
array 0.001730 1.000000
object 0.002057 1.189017
object2 0.002616 1.512139

こうして見るとPHP4/5共に配列でもオブジェクトでもそれほど差がありませんね。ただやはりPHP5のobject2だけが遅いのが気になります。

 

生成以外は配列とオブジェクトでそれほど差が生まれなかったのは意外でした。ただ以前DBから大量のレコードセットを配列に格納した場合とオブジェクトに格納した場合で大きなパフォーマンス差が生まれた事があったので、メモリ消費量など実行時間以外の要素で差があるのかもしれません。こちらもまた検証してみたいですね。

# PHP4と5でおおよそ2倍程度のパフォーマンス差がありました。PHP5を使う理由がまた一つ増えましたね。はい。

CakePHPのコーディング規約

この記事の所要時間: 113

CakePHPにもコーディング規約があります。

Cake Developers will use the following coding standards.
It is recommended that others developing CakeIngredients follow the same standards.

Developement/CodingStandards – CakePHP : Rapid Development Framework – Trac (2006-10-12)

PHP.PL DevTeamのコーディング規約が元になっているようです。内容をざっと見た感じではZend Frameworkのコーディング規約に似ていますね。

まあフレームワーク自体が規約に従っていないのはアレですが。

We agreed on using four space characters for indentation.

Developement/CodingStandards – CakePHP : Rapid Development Framework – Trac (2006-10-12)

規約ではインデントは4スペースになってますが、[cake/libs/model/model.php]等々を見るとインデントはtabになってたり。。

PHPのオーバーロード

  • 2006-10-06 (金)
  • PHP
この記事の所要時間: 30

JavaやC/C++など一般的な言語でのオーバーロードとPHPでいうオーバーロードは違います。

一般的なオーバーロードの定義は下のとおりです。

プログラミングにおいて、戻り値や引数の数やデータ型(シグネチャ)が異なる同名の関数やメソッドを多重定義すること。

オーバーロードとは 【overload】 ─ 意味・解説 : IT用語辞典 e-Words (2006-10-06)

Javaで書くとこんな感じです。

class Hoge {
  public void foo() {
  }

  public void foo(String bar) {
  }

  public void foo(int bar) {
  }

  public void foo(int bar, boolean flag) {
  }
}

同じfooメソッドを呼んでも引数によって実際に呼ばれるメソッドが変わります。

これをPHPで書くとこんな感じです。

< ?php
class Hoge {
  // 引数が一個だけなら
  function foo($bar) {
  }

  // 引数の数が変化するなら
  function foo() {
    $args = func_get_args();
  }
}
?>

厳密にはオーバーロードでは無いでしょうけど同じように動作するのでこれで良いと思っていました。ですのである日、PHPでオーバーロードができるようになった、と聞いてもピンッと来ませんでした。

PHPでいうオーバーロードは以下のような感じです。

この拡張モジュールの用途は、オブジェクトのプロパティへのアクセスと メソッドのコールのオーバーロードを可能にすることです。

オブジェクトプロパティとメソッドコールのオーバーロード (2006-10-06)

class Hoge {
  // PHP4
  function __call($method, $params, &$return) {
  }

  // PHP5
  function __call($method, $params) {
  }
}
// PHP4
overload('Hoge');
?>

この場合Hogeクラスに定義されていないメソッドを呼ぶと__callが呼ばれます。

つまりPHPでいうオーバーロードは「定義された変数、メソッドが無い場合に呼ばれるメソッド」と言った意味合いになってます。

他のLL言語にも「PHPのオーバーロード」のような機能はある(Perl:AUTOLOAD/Ruby:method_missing/Python:__call__?)のですが、「オーバーロード」という表現ではありません。(「オーバーロード」はC/C++と同じ演算子オーバーロードで使われています)

なぜPHPはこの機能に「オーバーロード」と名付けたのでしょうか。。。

 

はじめてC++でオーバーロードを見た時に「おースマートだ」と感激しました。「オーバーロード」という響きも好きですし、この言葉にはちょっと思い入れがあったので気になっていました。まあ他言語から移る方はお気をつけて、という事で。
# 昔オーバーロードとオーバーライドがごちゃごちゃになってたのはナイショです。:-P

Google Code Search-ソースコード検索サイト

この記事の所要時間: 127

Google Code Searchがリリースされました。

Googleは米国時間10月5日、新サービス「Google Code Search」を発表した。プログラマーはこのサービスを利用して膨大な数のソースコードを検索できるという。

グーグル、コード検索の新サービス「Google Code Search」を発表 – CNET Japan (2006-10-05)

関数をマニュアルで調べるのも重要なのですが、実際の使用例を見るのもとても参考になるので、こういうサービスはとても有り難いですね。まあ関数で脆弱性が発見された場合は速攻探されてしまいますが。。。

キーワードには正規表現も使えますし、(プログラム)言語やパッケージ名・ライセンス・ファイルの種類も指定できます。

次はAPIを待ちましょう。;-)

■ソースコード検索サイトリスト

include_pathかset_include_path()か

  • 2006-10-05 (木)
  • PHP
この記事の所要時間: 411

include_pathを設定する方法には、大きく分けて2通りあります。設定ファイル(php.ini/httpd.conf/.htaccess等)に記述する方法とPHPソースに記述する方法です。

記述例

設定ファイルに記述

; php.ini
include_path = ".:/usr/local/lib/php/pear"

; httpd.conf / .htaccess
php_value include_path ".:/usr/local/lib/php/pear"

PHPソースに記述

< ?php
$lib = dirname(dirname(__FILE__)) . "/lib";

// PHP4.3.0以降
set_include_path(get_include_path() . PATH_SEPARATOR . $lib);

// 全バージョン対応
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . $lib);
?>

 

どちらの方法でも動作はしますが、どちらがより良いか考えてみました。

記述方法

それぞれの利点・欠点を挙げてみました。

  設定ファイル PHPソース
良い点 ・設定項目がまとまっているので把握しやすい。
・ソースと設定を分離できる。
・動的に記述できる。
・環境に依存せず動作する。
いまいちな点 ・固定値しか設定できない。(動的に変更できない。)
・影響範囲が大きいので局所的な設定には不向き。
・httpd.conf/.htaccessの設定はCLI環境では反映されない。
・他のソースから読み込まれると影響範囲が把握し辛い。
・ソース内に混在する。

どちらにも一長一短があります。

記述場所

各記述場所は以下のとおりです。並びは設定の影響範囲順になっています。(下にいくほど影響範囲が狭くなっています。)

記述方法 記述場所 要root権限 環境依存
設定ファイル php.ini
設定ファイル httpd.conf
設定ファイル .htaccess
httpd.confで使用禁止になっている場合がある。
PHPソース インクルードファイル
各ソースで読み込む共通ソース。
PHPソース 単一のソースファイル

これを見るとどんな環境でも使えるのはやはりPHPソースですね※1。特にソースを配布する場合はPHPソースに記述する方が使用する側は手間がかからなくて良いです。

どちらが良いか

記述場所で考えると設定ファイルは制限があるように見えますが、私が普段携わっている案件ではphp.ini/httpd.confを(直接的にせよ間接的にせよ)触れる事がほとんどですし、もし触れない場合でも.htaccessが使えるようにしてもらえば特に問題無いかと思います。(.htaccessすら設定できない環境向けに開発する方が珍しいかと)

include_pathはJavaのclasspathと同じような感覚で捉えているので、ソースには書かず設定ファイルに書く方がしっくりきます。またmbstringやらmod_rewriteやら設定する事が多いので、それらと同じところに書いておけば設定を把握しやすいです。

実際の記述ですが、php.iniはデフォルトのまま or PEARディレクトリのみ記述。httpd.conf/.htaccessにサイト(ディレクトリ)共通設定を記述。これで基本的には終了です。CLIなどでPHPソース単体で設定が必要な場合のみソース内に記述するようにしています。

 

ただし上記で少し触れたようにソース配布を前提とした場合はソースに書くのもありだと思います。(もちろんその場合も共通ファイルを作成し、各スクリプトからはそれを読み込む形にした方が良いでしょう。)

 

※1もちろんdisable_functionsで無効になっている場合は別ですが。

display_errorsはoffに

  • 2006-10-04 (水)
  • PHP
この記事の所要時間: 028

本稼働のサイトではdisplay_errorsはoffにしときましょう。でないと晒されてしまいます。

最近はあまり見ませんが、以前はちょこちょこWarningやらNoticeやら表示しているサイトがありました。(SUNのサイトでJavaがスタックトレースを吐いているのもありましたね。。。)人の振り見て我が振り直せで気を付けましょう。

 

実は一番気になったのは[/home/php/cakephp/cake/bootstrap.php]だったり:-)

ホーム > PHP

検索
フィード
メタ情報

Return to page top