fixedpoint.jp - PHP Coding Standards




PHP Coding Standards

PHP は多くのライブラリを持っています。それらは言語のコアを実装している C で書かれている場合と、PHP 自体で書かれている場合があります。前者の場合について、多くの開発者や利用者に便宜を図る目的で、コーディング規約が用意されています: http://cvs.php.net/viewvc.cgi/php-src/CODING_STANDARDS

あくまで規約なのでそれぞれの項目の内容の賛否はあるにしても、C のコードを書くときの参考になります。

以下がその拙訳です; Revision 1.32.4.3 に対応しています。

PHP Coding Standards(PHP コーディング規約)
==========================================

このファイルは、PHP でコードを追加したり更新したりするプログラマが従うべき
いろいろな規約を挙げている。このファイルは PHP v3.0 の開発のごく遅い段階で
追加されたので、(まだ)コードベースがそれに従っていないが、その一般的な方向に
向かいつつある。我々はバージョン4リリースに取り組んでいるため、多くの
セクションはこのルールを使って書き直されている。

Code Implementation(コード実装)
===============================
[0] ソースファイルおよびマニュアルの中でコードに文書を与えること。

[1] リソースへのポインタを(引数として)与えられた関数ではそれらを解放
    するべきでない。

    例えば、関数 int mail(char *to, char *from) では to や from を解放
    するべきでない。
    例外:

      - その関数の意図された振舞いがそのリソースを解放すること。例として efree()
      - その関数に1つの真理値をとる引数が与えられている(真なら - その関数で
        ポインタ引数を解放しなけらばならず、偽なら - 解放してはいけない)
      - 低レベルなパーサルーティンで、メモリのコピーを最小限にするために
        トークンのキャッシュおよび bison コードと緊密に統合されている

[2] 同じモジュール内で他の関数と緊密に統合されている関数で、互いの自明でない
    振舞いに基づいているものは、そのとおり文書で説明されるべきであり、かつ 
    'static' と宣言されるべきだ。可能ならばそれらの関数を避けるべきだ。

[3] 可能な場合は常に定義とマクロを使うこと、定数は意味のある名前を持つよう
    にし操作しやすいようにすること。この規則の唯一の例外が0と1で、(それぞれ
    順に)偽と真として使われる場合である。1つの #define をしてから、異なる
    振る舞いや行為を指定する数値定数を使うべきだ。

[4] 文字列を扱う関数を書くときは、PHP は各文字列の length プロパティを保持
    すること、そしてそれを strlen() で計算するべきでないことを忘れないように
    すること。効率のため、かつ関数をバイナリセーフにするために length 
    プロパティを有効に活用するよう関数を書くこと。
    文字列を変更し、変更しながらその新しい長さを取得する関数はその新しい長さ
    を返すべきであり、それによって strlen() で再計算しなくてもよくなる。
    (例えば php_addslashed() のように。)

[5] strncat() を絶対に使わないこと。あなたがしようとしていることが分かって
    いると絶対に確信があり、再度 strncat() の man ページを確認したときに、
    そしてそのときにのみ、それを使うことを考えること。そしてそれでもなお
    避けるよう試みること。

[6] PHP のソースでは PHP_* マクロを使うこと、そしてソースの Zend の部分では 
    ZEND_* マクロを使うこと。PHP_* マクロのほとんどは ZEND_* マクロの別名と
    されているが、そうすることであなたが呼んでいるマクロがどちらの種類かが
    よりよく理解できる。

[7] #if 文を使ってコードをコメントアウトするときには、0だけで使わないこと。
    代わりに "<cvs username here>_0" を使うこと。例えば、 #if FOO_0、ただし 
    FOO はあなたの cvs user foo である。これによって、特にバンドルされた
    ライブラリの中でなぜコードがコメントアウトされているのかがより追跡し
    やすくなる。

[8] 利用できない関数を定義しないこと。例えば、あるライブラリで1つの関数が
    見当たらないとき、その関数の PHP 版を定義しないこと、そして存在しない関数
    についての実行時のエラーを生起しないこと。エンドユーザーは関数の存在を
    テストするために function_exists() を使うべきである。

[9] 標準 C ライブラリの同類の関数よりも emalloc()、efree()、estrdup() などを
    使うこと。これらの関数は、リクエストの最後に解放されていないメモリの割り当て
    除去を保証する、内部的な"安全ネット"機構を実装している。これらの関数は
    また、デバグモードで動かす時に割り当てやオーバフローの便利な情報を与えて
    くれる。

    ほとんど全ての場合エンジンへ戻すメモリは emalloc() を使って割り当てるべきだ。

    malloc() を使用するのは、サードパーティのライブラリでそのメモリを制御
    したり解放したりする必要があるかもしれない場合、または当該のメモリが複数
    のリクエストの間で生き残る必要がある場合だけに限るべきである。

Naming Convention(命名規則)
===========================

[1] ユーザーレベルの関数のための関数名は PHP_FUNCTION() マクロの中に閉じ込める
    べきだ。その関数名は小文字に限るべきで、単語の区切りはアンダースコアで、
    極力文字数を少なくすること。その関数名自身の可読性が大きく損なわれるとき
    には省略を使うべきではない。

    良い:
    'mcrypt_enc_self_test'
    'mysql_list_fields'

    まあまあ:
    'mcrypt_module_get_algo_supported_key_sizes'
    ('mcrypt_mod_get_algo_sup_key_sizes' にしたら?)
    'get_html_translation_table'
    ('html_get_trans_table' にしたら?)

    悪い:
    'hw_GetObjectByQueryCollObj'
    'pg_setclientencoding'
    'jf_n_s_i'

[2] ある"親セット"の一部の関数の1つだった場合は、そのユーザー関数名にその
    親が含まれるべきであり、その親プログラムまたは関数族にはっきりと関連づけ
    るべきだ。これは parent_* の形にするべきだ。

    'foo' 関数の族なら例えば、
    良い:
    'foo_select_bar'
    'foo_insert_baz'
    'foo_delete_baz'

    悪い:
    'fooselect_bar'
    'fooinsertbaz'
    'delete_foo_baz'

[3] ユーザー関数によって使われる関数名には "_php_" が前置されるべきであり、
    続けて、単語をアンダースコアで区切りながら、小文字で、その関数を説明する
    ような名前にすること。もし適用できるなら、'static' と宣言されるべきだ。

[4] 変数名は意味のあるものにするべきだ。1文字の変数は避けなければならないが、
    例外としてその変数が本当の意味を持たない、または自明な意味をもつ場合
    (例えば for (i=0; i<100; i++) ...)がある。

[5] 変数名は小文字にするべきだ。単語の間を分けるためにはアンダースコアを使うこと。

[6] メソッド名は 'studlyCaps' 命名規則(または 'bumpy case' や 'camel caps' 
    といわれるもの)に従うべきで、極力文字数をすくなくすること。名前の最初の
    文字は小文字で、新しい'単語'が始まる文字は大文字となる。

    良い:
    'connect()'
    'getData()'
    'buildSomeWidget()'

    悪い:
    'get_Data()'
    'buildsomewidget'
    'getI()'

[7] クラスには説明になる名前を与えるべきだ。できれば省略を使わないようにせよ。
    クラス名の中の各単語は区切りにアンダースコアを置かずに大文字で始まるべき
    である(CampelCaps は大文字で始まっている)。クラス名の先頭には'親セット'の
    名前を置くべきだ(例えば、拡張子の名前)。

    良い:
    'Curl'
    'FooBar'

    悪い:
    'foobar'
    'foo_bar'

Syntax and indentation(構文とインデント)
========================================

[1] C++ スタイルのコメント(つまり // コメント)を絶対に使わないこと。代わりに
    常に C スタイルのコメントを使うこと。PHP は C で書かれており、どの ANSI-C 
    コンパイラでもコンパイルできることを目指している。たとえ多くのコンパイラが 
    C のコードの中の C++ スタイルのコメントを受け入れるとしても、あなたの
    コードが他のコンパイラでも同じようにコンパイルできることを保証しなければ
   ならない。
   この規則の唯一の例外が Win32 に特化されたコードであり、というのも Win32 へ
   の移植は MS-Visual C++ に特化されていて、このコンパイラは C コードの中の 
   C++ スタイルのコメントを受け入れるからである。

[2] K&R スタイルを使うこと。もちろん、我々は誰かにこれまでその人が使っていな
    かったスタイルを使うよう強制することはできないし、またしたくもないが、
    本当に少なくともこの場合、PHP のコアまたは標準モジュールの中に入れるコード
    を書くときに限っては、K&R スタイルを維持すること。この適用は全てに関して
    であり、インデントやコメントのスタイルに始まって関数の宣言のスタイルに
    至るまで全てである。

    (http://www.catb.org/~esr/jargon/html/I/indent-style.html も参照すること)

[3] 惜しみなく空白と括弧を入れること。常に
    if (foo) {
        bar;
    }

    は

    if(foo)bar;

    より好ましい。
  ブロックの中では変数の宣言のセクションとステートメントとの間に1つ空行を置く
    こと。同様に論理的なステートメントのグループの間に空行を置くこと。2つの関数
    の間には少なくとも1つ、できれば2つのほうがよいが、空行を置くこと。

[4] インデントにはタブ文字を使うこと。1つのタブは4つの空白を表現するものと
    みなされる。定義、コメント、そして制御構造が正確に並ぶようにインデントに
    一貫性を持たせることが大切である。

[5] プリプロセッサのステートメント(#if など)は行頭から開始すること。プリプロセッサ
    のディレクティブをインデントするには、# を行頭において、任意の数の空白を
    続けること。

Testing(テスト)
===============

[1] 拡張は *.phpt を使って十分テストするべきである。それについては 
    README.TESTING をよむこと。

Documentation and Folding Hooks(ドキュメンテーションと折り畳みフック)
=====================================================================

オンラインドキュメンテーションがコードと並ぶように、各ユーザーレベル関数に
ついてはその関数が行うことを説明する簡単な1行の前にそのユーザーレベル関数
プロトタイプを持つべきである。それはこのように見えるだろう:

/* {{{ proto int abs(int number)
   Returns the absolute value of the number */
PHP_FUNCTION(abs)
{
   ...
}
/* }}} */

この {{{ 記号は Emacs や vim (set fdm=marker) の折り畳みモードでのデフォルトの
折り畳み記号である。非常に大きなファイルを扱うときに折り畳みは非常に便利である。
というのもファイルを素早くスクロールすることができ、あなたが作業したい関数だけ
折り畳みを解けばいいからである。各関数の最後の }}} は折り畳みの最後を示しており、
別の1行に置くべきである。

そこにある "proto" キーワードは単に全体的な関数のサマリーを生成する 
doc/genfuncsummary スクリプトを補助する。関数プロトタイプの前にこのキーワード
があることで、関数のサマリーを乱雑にすることなくコードの他のどこかを折り畳む
ことができる。

省略可能な引数はこのように書かれる:

/* {{{ proto object imap_header(int stream_id, int msg_no [, int from_length [, int subject_length [, string default_host]]])
   Returns a header object with the defined parameters */

そう、たとえ行が長くなってもプロトタイプを1つの行に収めるようにすること。

New and Experimental Functions(新しい実験的な関数)
==================================================
新しい関数群の最初の公式実装に通常伴う問題を減らすために、最初の実装では 
'EXPERIMENTAL' とラベル付けされたファイルをその関数のディレクトリに含め、
その初期の実装期間では標準的な前置記法のきまりに従うことでそうと分かる
ようにすること。

'EXPERIMENTAL' とラベル付けされたファイルには次の情報を含めるべきである:
   任意の製作について情報(知られているバグ、そのモジュールの将来の方向)
   CVS コメントには適さない進行中の状態についての注意

Aliases & Legacy Documentation(別名とレガシードキュメンテーション)
==================================================================
重複する名前に良く似た控えるべき別名を持つことがあるだろう、例えば、
somedb_select_result と somedb_selectresult である。
ドキュメンテーションの目的から、これらは最近の名前でのみ文書にされており、
親関数のドキュメンテーションの中で別名が挙げられている。参照のし易さから、
ユーザー関数で完全に異なる名前を持ち、同じ関数の別名である(highlight_file と 
show_source のような)ものは分けて文書にされる。プロトタイプはそれでもなお含ま
れるべきで、どの関数が別名とされているかを説明するべきである。

後方互換のための関数と名前は、そのコードがコードベースの一部分として正当に保つ
ことのできる限りは、維持されるべきである。ドキュメンテーションに関するさらなる
情報は /phpdoc/README を見ること。

© 2006,2007 Takeshi Abe