Drupalコーディング規約

  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • warning: Creating default object from empty value in /home/groups/d/dr/drupal-jp/htdocs/main/sites/all/modules/spam/spam.module on line 548.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.
  • : Function ereg() is deprecated in /home/groups/d/dr/drupal-jp/htdocs/main/includes/file.inc on line 649.

以下の文章は、Drupal Coding Standardsの記事を意訳したものです。 誤訳がありましたら適当に修正して下さい。また入力フィルターの影響かわかりませんが、意図しない所で行間があいてしまったりしているので、適切に整形出来るようでしたら、そちらの修正も御願い致します。



注釈:Drupalコーディング規約はDrupalに組み込まれるコードに適用されます。
この規約は、PEAR Coding standardsを参考にして作成されました。



インデント


2つのスペースを1つのインデントとして使用します。インデントとしてタブは使用しません。

制御構造


if, for, while, swithなどの制御構造の記述について。例としてそれらの中で最も複雑なifステートメントの例を記載します。
if (condition1 || condition2) {
  action1;
}
elseif (condition3 && condition4) {
  action2;
}
else {
  defaultaction;
}

制御文を関数呼び出しと区別する為に、制御キーワードと括弧の間には1つのスペースを挿入します。
技術的にはオプションであっても、常に中括弧を使用する事が強く推奨されます。そうする事によって、可読性が向上し、行が追加された時のロジックエラーの発生を減少出来ます。

switch文の場合の例:

switch (condition) {
  case 1:
    action1;
    break;

  case 2:
    action2;
    break;

  default:
    defaultaction;
    break;
}



関数呼び出し


関数を記述する際は、関数名と左括弧、最初のパラメータの間にはスペースを挿入しません。またカンマと各パラメータの間にはスペースを挿入し、最後のパラメータと右括弧、右括弧とセミコロンの間にはスペースを挿入しません。以下、例を記載します。
$var = foo($bar, $baz, $quux);
上記のように、関数の戻り値を変数に代入する場合は、イコール記号の両端に1つづつスペースを挿入します。
関連した値の代入ブロックの場合は、可読性を向上させる為に1つ以上のスペースを挿入しても構いません。
$short         = foo($bar);
$long_variable = foo($baz);


関数定義


function funstuff_system($field) {
  $system["description"] = t("This module inserts funny text into posts randomly.");
  return $system[$field];
}
デフォルト値を持つ引数は、引数リストの最後にします。
値を返す関数の場合は、どんな条件でも必ず値を返すようにします。

配列


配列は、それぞれの要素間と代入演算子との間に1つのスペースを挿入します。
$some_array = array('hello', 'world', 'foo' => 'bar');
もし1行が80文字以上になる場合(フォームやメニュー定義の場合は、よくそうなります)は、おのおのの要素を1行に分割して、1レベルインデントします。
$form['title'] = array(
  '#type' => 'textfield',
  '#title' => t('Title'),
  '#size' => 60,
  '#maxlength' => 128,
  '#description' => t('The title of your node.'),
);

最後の配列要素の後ろにあるカンマはタイプミスではありません!
そうする事によって、もし別の配列要素を最後に追加する事になった場合でも、エラーが発生する事を防ぐ事が出来ます。

コメント


クラスの内容を記載するインラインドキュメントは、Doxygenの規約にのっとって記載します。
Doxygenについてのより詳しい情報は、以下をご参照ください。
Drupalは次のドキュメントブロック構文を使用します。
/**
 * Comments.
 */

またDoxygenコマンドは、/ ではなく @ をプレフィックスとして使用します。
ドキュメント生成の為でないコメントも強く推奨されます。
一般的な経験則として、コードブロックを見たときに「再度作成したくないなぁ」と思う場合は、忘れる前にそれらがどのような働きをするかを記述するべきでしょう。
Cスタイルのコメント(/* */)とC++標準のコメント(//)のどちらも使用できます。
Perl/shellスタイルのコメント(#)は使用できません。

インクルードコード


無条件にクラスファイルをインクルードする場合は、require_once()を使用します。また条件付でクラスファイルをインクルードする場合(例えばfactoryメソッドのように)は、include_once()を使用します。
どちらの場合でもファイルは、一度だけインクルードされる事が保証されます。
それらは同じファイルリストを共有する為、require_once()によってインクルードされたファイルが、include_once()で再度インクルードされる事を心配する必要はありません。

注意: include_once()とrequire_once()は関数ではなく、ステートメントなので、挿入されるファイル名についての説明を記載する必要はありません。



PHPコードタグ


PHPのコード範囲を定める場合は、省略形の<? ?>ではなく、常に<?php ?> を使用します。
これは、Drupalの規約というだけでなく、異なったオペレーションシステムや環境にPHPコードを移植し易くする為の方法でもあります。
すべてのコードファイル(モジュールやインクルードファイルなど)において、最後の?>は、省略するという事に気をつけて下さい。
クロージングデリミタは"?>"はオプションであり、それを取り除く事によってシステム上のどこかで問題を引き起こしかねないファイル最終行の空白を予防出来ます。
これについてのより詳細な情報は、PHP Code tagsをご参照下さい。

ヘッダコメントブロック


Drupalのコアとして配布されるすべてのソースコードは、以下の
コメントブロックをヘッダとして含める必要があります。
<?php
// $Id$

このタグは、CVSによって以下のような有用な情報に変換されます。
<?php
// $Id: CODING_STANDARDS.html,v 1.7 2005/11/06 02:03:52 webchick Exp $


CVSの使用方法


おのおののファイルにCVSキーワードの"Id"を含めます。
ファイル編集時にもしIdが含まれていなかった場合は記述を追加し、"Last Modified:"などのような表記になっていた場合は、それを置換します。

この章の以下の文章は、あなたがCVSタグとブランチについての基本的な知識をもっていると仮定して記述しています。

CVSタグは、あなたのパッケージファイルのどのリビジョンが特定のリリースに所属しているかをラベル付けする為に使用されます。
以下は、必要なCVSタグの一覧です。

DRUPAL-X-Y

(必須)リリースをタグ付けするのに使用する。
もしこのタグを使用しない場合は、CVSサーバーからリリース時の状態のパッケージを取得する方法がなくなります。



サンプルURL


すべてのサンプルURLとして、RFC 2606に準拠した "example.com"を使用します

ネーミングルール


関数とメソッド
関数名とメソッド名は、アンダーバーで接続された小文字の単語にします。さらに、関数名はモジュール間での名称の重複をさける為に、モジュール名をプレフィックスとして使用します。
プライベートクラスメンバー(宣言されたクラスの中からしか使用されないクラスメンバー;PHP4は正しい制約をもったプライベートネームスペースをサポートしません)は、1つのアンダーバーで始まる名称にします。以下、例を示します。
_node_get()
$this->_status

定数
定数はすべて大文字にし、アンダーバーで単語を接続する名称にします。
また定数が含まれるモジュール名の大文字をプレフィックスとして使用します。

グローバル変数
グローバル変数を定義する必要がある場合は、1つのアンダーバーにモジュール/テーマ名を続け、さらにアンダーバーを続ける名称にします。
注意
規約上は上記のようになっていますが、実際には、下記の例のように"モジュール/テーマ名"にアンダーバーを続ける名称で定義されている場合が多いようです。
recaptchaモジュールの例
$recaptcha_api_server

ファイル名
すべてのドキュメントファイルは、Windowsで参照し易いように ".txt"拡張子を付けます。またファイル名はすべて大文字(readme.txt ではなく、README.txt)、拡張子はすべて小文字(TXT ではなく txt)にします。
例: README.txt, INSTALL.txt, TODO.txt, CHANGELOG.txt など



改行コード


以下は翻訳内容ではなく、訳者の追記事項です。

改行コードについての規約は記載されていませんが、Drupalコアの内容を参照すると以下のようになっていますので、それに倣った方が無難だと思います。

モジュール関連ファイル(.module, .inc, .info, .install)
Unixフォーマット改行コード(\n)

テーマ関連ファイル(.tpl.php, template.php, .css)
Windowsフォーマット改行コード(\r\n)

ドキュメントファイル(.txt)
Windowsフォーマット改行コード(\r\n)

コメント

コーディング規約の自動チェック

追加情報
Coderモジュール を使う事によって、プログラム中のコーディング規約に違反している箇所とエラー理由を表示出来るようです。

性能・セキュリティまで

Coderモジュールのページを見てみましたが,規約チェックにとどまらず,性能改善のためのアドバイスやセキュリティチェックまでサポートするモジュールを目指して,開発が活発に進められているようですね。

http://drupal.org/node/121388
ここを見ても「なかなか一筋縄ではいかないなぁ」などと思ってしまうのですが,でも頑張って欲しいところです。

すばらしい!!

APIリファレンス以外では、最も参照されるドキュメントですね。

「if one is appropriate」は、「適切なら」でいいんじゃないでしょうか。
値を返さないサブルーチンタイプの関数は除外する、という意味だと思います。
逆に、値を返す関数の場合は、returnを書かずにNULLが返ることを期待せずに、ちゃんとreturnを書けってことでしょう。
私は従ってなかったりしますが。(^^;;

ありがとうございます。

修正しておきました。
なんとなくそうかと思ったのですが、自信がなかったので助かりました。

あと、その他の疑問点として、

wrote:
グローバル変数
グローバル変数を定義する必要がある場合は、1つのアンダーバーにモジュール/テーマ名を続け、さらにアンダーバーを続ける名称にします。

とされてますが、そのような実例をあまり見たことがないので、これは守る必要があるのかちょっと疑問です。
(Pearの記述にならったのだと思いますが。)

実例・・?

kabetaniさん,コーディング規約の訳をありがとうございます。

グローバル変数の定義ですが,私の環境に入ってるモジュール内を調べてみました。global 式の書いてある行をgrepしています。コアの変数($user, $base_url, など)を参照する類は除くと,以下のような実例が見つかります。

./leech/leech.module:898: global $LEECH_PRERENDERED_ADDONS;
./spamspan/spamspan.module:120: global $spamspan_format;
./recaptcha/recaptcha.module:98: global $recaptcha_api_server, $recaptcha_api_s
ecure_server, $recaptcha_verify_server;

ですが,これらは規約の「1つのアンダーバーにモジュール/テーマ名を続け、さらにアンダーバーを続ける名称(原文:their name should start with a single underscore followed by the module/theme name and another underscore)」の,最初にアンダーバーを付ける決まりには従っていません・・・よね?$_spamspan_format などとするのが正しいのかなと。

このページの定義の個所に「例: ○○」というのを書き加えようかなと思って調べていたのですが,上記のような例しか見つからなかったので困りました・・・。勝手に定義通りに書き換える($_spamspan_format)のはまずいですし,かといって存在しないものをでっち上げるのも躊躇われます。

まぁそれはそれとして,最低限「モジュール/テーマ名から始める」という規約は擬似的な名前空間の分離になるので守ったほうがよさそうに思います。モジュール同士が競合して予期せぬバグが起こる可能性を考えると「とりあえず守っとけ」とするのが良いのではないでしょうか・・・。

Re:実例・・?

lockcoleさん、調査ありがとうございます。

やっぱりグローバル変数は「モジュール/テーマ名から始まる名称」で定義されている事が多いんですね。
規約と実装のどちらが正解なのかわからないので、とりあえず注記として追加しておきます。