【Drupal】PHPコーディング規約をまとめてみた
開発者にとって、仕事をする上で大切なことのひとつに、コーディング規約があります。
Drupalのように世界中の開発者がDrupalの開発や保守をする上でコーディング規約に沿って開発するのは重要なことです。またDrupalのカスタムモジュールを作成する場合も、複数人の開発者がプロジェクトに携わる場合にはコードをシェアできるようにあらかじめコーディング規約を取り決めて作業するのが、プロジェクトを成功に導く鍵になります。ここでは、Drupalのコーディング規約を日本語に翻訳してご紹介します。
Drupalのバックエンド側の処理はPHPで書かれています。Drupalが提案しているコーディング規約を翻訳しました(基本的にPEARコーディング規約に準拠しています)
https://www.drupal.org/docs/develop/standards/php/php-coding-standards
インデントと空白
タブを使用せず、スペース 2 個のインデントを使用します。
行末に空白を含めないでください。
ファイルは、\r\n (Windows の行末) ではなく、\n (Unix の行末) を行末としてフォーマットする必要があります。
すべてのテキスト ファイルは 1 つの改行 (\n) で終わる必要があります。 これにより、「\ ファイルの末尾に改行はありません」というパッチに関する冗長な警告が回避され、ファイルの末尾に行が追加されたときに何が変更されているかが明確になるため、パッチが読みやすくなります。
PHP ファイルの先頭にあるすべてのブロックは空行で区切る必要があります。 これには、 /** @file */
ブロック、名前空間宣言、および use
ステートメント (存在する場合) およびファイル内の後続のコード。 したがって、たとえば、ファイル ヘッダーは次のようになります。
<?php
namespace This\Is\The\Namespace;
use Drupal\foo\Bar;
/**
* Provides examples.
*/
class ExampleClassName {
または、非クラス ファイルの場合 (例: .module
):
<?php
/**
* @file
* Provides example functionality.
*/
use Drupal\foo\Bar;
/**
* Implements hook_help().
*/
function example_help($route_name) {
オペレーター
すべての二項演算子 (2 つの値の間の演算子)。 +
, -
, =
, !=
, ==
, >
、などは、読みやすくするために演算子の前後にスペースを入れる必要があります。 たとえば、割り当ては次のようにフォーマットする必要があります。 $foo = $bar;
それよりも $foo=$bar;
。 単項演算子 (1 つの値のみを操作する演算子)。 ++
、演算子と演算対象の変数または数値の間にスペースを入れないでください。
弱い型付き不等式のチェックでは、 !=
オペレーター。 の <>
演算子を PHP コードで使用してはなりません。
鋳造
キャスト内の (type) と $variable の間にスペースを入れます。 (int) $mynumber
.
制御構造
制御構造には、if、for、while、switch などが含まれます。その中で最も複雑な if ステートメントのサンプルを次に示します。
if (condition1 || condition2) {
action1;
}
elseif (condition3 && condition4) {
action2;
}
else {
defaultaction;
}
(注: 「else if」は使用しないでください。常に elseif を使用してください。)
制御ステートメントでは、関数呼び出しと区別するために、制御キーワードと開き括弧の間にスペースを 1 つ入れる必要があります。
中括弧が技術的にオプションである状況でも、常に中括弧を使用してください。 これらを使用すると、可読性が向上し、新しい行を追加するときに論理エラーが発生する可能性が低くなります。 開始カーリーは開始ステートメントと同じ行にあり、その前にスペースが 1 つ必要です。 終了カーリーは単独で 1 行に配置し、開始ステートメントと同じレベルにインデントする必要があります。
switch ステートメントの場合:
switch (condition) {
case 1:
action1;
break;
case 2:
action2;
break;
default:
defaultaction;
}
do-while ステートメントの場合:
do {
actions;
} while ($condition);
テンプレートの代替制御ステートメント構文
テンプレートでは、括弧の代わりに : を使用した代替制御ステートメント構文が許可されます。 コントロール キーワードの後の右括弧とコロンの間にスペースを入れてはならず、コントロール構造内の HTML/PHP はインデントする必要があることに注意してください。 例えば:
<?php if (!empty($item)): ?>
<p><?php print $item; ?></p>
<?php endif; ?>
<?php foreach ($items as $item): ?>
<p><?php print $item; ?></p>
<?php endforeach; ?>
行の長さと折り返し
コードには次のルールが適用されます。 参照してください。 「Doxygen とコメントの書式設定規則」を コメントに関するルールについては、
- 一般に、コードのすべての行は 80 文字を超えてはなりません。
- 長い関数名、関数/クラス定義、変数宣言などを含む行は 80 文字を超えることができます。
- 制御構造の条件は、読みやすく理解できるものであれば、80 文字を超える場合があります。
if ($something['with']['something']['else']['in']['here'] == mymodule_check_something($whatever['else'])) {
...
}
if (isset($something['what']['ever']) && $something['what']['ever'] > $infinite && user_access('galaxy')) {
...
}
// Non-obvious conditions of low complexity are also acceptable, but should
// always be documented, explaining WHY a particular check is done.
if (preg_match('@(/|\\)(\.\.|~)@', $target) && strpos($target_dir, $repository) !== 0) {
return FALSE;
}
- 条件を複数行に折り返さないでください。
- 制御構造の条件は、「コードの最小行数で最もコンパクトな条件賞」™ を獲得しようとしてはいけません
// DON'T DO THIS!
if ((isset($key) && !empty($user->uid) && $key == $user->uid) || (isset($user->cache) ? $user->cache : '') == ip_address() || isset($value) && $value >= time())) {
...
}
代わりに、条件を分割して個別に準備することをお勧めします。これにより、条件の根本的な理由を文書化することもできます。
// Key is only valid if it matches the current user's ID, as otherwise other
// users could access any user's things.
$is_valid_user = isset($key) && !empty($user->uid) && $key == $user->uid;
// IP must match the cache to prevent session spoofing.
$is_valid_cache = isset($user->cache) ? $user->cache == ip_address() : FALSE;
// Alternatively, if the request query parameter is in the future, then it
// is always valid, because the galaxy will implode and collapse anyway.
$is_valid_query = $is_valid_cache || (isset($value) && $value >= time());
if ($is_valid_user || $is_valid_query) {
...
}
注: この例はまだ少し密度が濃いです。 コードに詳しくない人でもロジックを理解できるかどうかを常に自分で検討し、判断してください。
関数呼び出し
関数は、関数名、開き括弧、最初のパラメータの間にスペースを入れずに呼び出す必要があります。 カンマと各パラメータの間にはスペースを入れてください。最後のパラメータ、右括弧、セミコロンの間にはスペースを入れません。
以下に例を示します。
$var = foo($bar, $baz, $quux);
関数の宣言
function funstuff_system($field) {
$system["description"] = t("This module inserts funny text into posts randomly.");
return $system[$field];
}
デフォルト値を持つ引数は、引数リストの最後に置かれます。 適切な場合は、常に関数から意味のある値を返すようにしてください。
匿名関数では、次の例のように、「関数」とそのパラメーターの間にスペースが必要です。
array_map(function ($item) use ($id) {
return $item[$id];
}, $items);
クラスコンストラクターの呼び出し
引数なしでクラス コンストラクターを呼び出す場合は、必ずかっこを含めてください。
$foo = new MyClassName();
これは、引数を持つコンストラクターとの一貫性を維持するためです。
$foo = new MyClassName($arg1, $arg2);
クラス名が変数の場合、最初に変数が評価されてクラス名が取得され、その後コンストラクターが呼び出されることに注意してください。 同じ構文を使用します。
$bar = 'MyClassName';
$foo = new $bar();
$foo = new $bar($arg1, $arg2);
パラメータと戻り値のタイプヒンティング
Drupal 9 以降では、パラメータと戻りタイプヒントを可能な限り使用する必要があります。 パラメーターと戻り値のタイプヒントを使用した関数定義の例:
public function myMethod(MyClass $myClass, string $id): array {
// Method code here.
}
新しい機能とメソッド
パラメータと戻り値のタイプヒントは、既存のクラスとインターフェイスのメソッドの新しい子実装を含む、すべての新しい関数とメソッドに含める必要があります。
既存の機能とメソッド
既存のコードにタイプヒントを追加すると、下位互換性が失われます。 以前のマイナー バージョンで非推奨の警告が初めて発生した場合は、タイプヒントをメジャー バージョンに追加できます (また追加する必要があります)。 #3050720: [メタ] 戦略と進行中の議論のために、既存のコードに厳密な型付けを実装するを 参照してください。
特定のデータ型に関する注意事項
混合データ型
mixed
これは、より具体的なデータ型を識別できないまれなケースでのみ必要になります (たとえば、コールバックの戻り値、またはマークアップ オブジェクトまたはスカラー文字列のいずれかであるマークアップ文字列の場合)。 必要性 mixed
または、 共用体型は コードをリファクタリングする必要がある可能性があることを示していることがよくあります。
Null 許容型
使用します。 許容型を データ型が特定の型または null のいずれかである null
オブジェクト
パラメーターと戻り値の型 (クラスではなく) にはインターフェイスの typehint を使用します。 考えられるすべてのパラメータまたは戻り値を含む、最も具体的なインターフェイスを入力ヒントとして入力します。 stdClass
を使ってはいけません .
空文字
関数またはメソッドが何も返さない場合は、 void
タイプヒント。
配列
配列は、各要素 (カンマの後) をスペースで区切る短い配列構文を使用し、該当する場合は => キー関連付け演算子の前後にスペースを使用してフトするォーマッ必要があります。
$some_array = ['hello', 'world', 'foo' => 'bar'];
配列を宣言する行が 80 文字を超える場合 (フォームやメニューの宣言の場合がよくあります)、各要素を独自の行に分割し、1 レベルインデントする必要があることに注意してください。
$form['title'] = [
'#type' => 'textfield',
'#title' => t('Title'),
'#size' => 60,
'#maxlength' => 128,
'#description' => t('The title of your node.'),
];
上で見たように、複数行の配列では、最後の配列要素の後にカンマがなければならないことに注意してください。 これにより、後で別の要素がリストの最後に配置された場合の解析エラーを防ぐことができます。
短い配列構文は、5.4 より前のバージョンの PHP ではサポートされていないことに注意してください。 これは、明示的な PHP 5.4 以降の要件を持たない Drupal 7 コアおよび Drupal 7 コントリビュート プロジェクトでは、長い配列構文を使用する必要があることを意味します。
引用句
Drupal には、一重引用符と二重引用符の使用に関する厳密な基準はありません。 可能であれば、各モジュール内の一貫性を保ち、他の開発者の個人的なスタイルを尊重してください。
この注意点を念頭に置いて、デフォルトでは一重引用符文字列を使用する必要があります。 次の 2 つの場合を除いて、これらの使用が推奨されます。
- 意図的なインライン変数補間 (例: "<h2>$header</h2>")。
- 文字列を二重引用符で囲むことにより、一重引用符のエスケープを回避できる翻訳済み文字列。 そのような文字列の 1 つは、「彼は良い人です」です。 それは「彼は良い人です。」です。 一重引用符で囲みます。 このようなエスケープは、テキスト翻訳用の .pot ファイル ジェネレーターによって適切に処理されない可能性があり、また、読むのがやや不便です。
文字列操作
読みやすくするために、ドットと連結部分の間には必ずスペースを入れてください。
<?php
$string = 'Foo' . $bar;
$string = $bar . 'foo';
$string = bar() . 'foo';
$string = 'foo' . 'bar';
?>
単純な変数を連結する場合は、二重引用符を使用してその中に変数を追加できます。 それ以外の場合は一重引用符を使用します。
<?php
$string = "Foo $bar";
?>
連結代入演算子 (「.=」) を使用する場合は、代入演算子の場合と同様に、両側にスペースを使用します。
<?php
$string .= 'Foo';
$string .= $bar;
$string .= baz();
?>
コメントの記述
コメントの標準については、別の Doxygen とコメントの書式設定規則のページ で説明されています。
コードの再利用
クラスファイルを無条件にインクルードする場合はどこでも、次を使用します。 require_once()
。 条件付きでクラス ファイル (ファクトリ メソッドなど) を含める場合はどこでも、次を使用します。 include_once()
。 これらのいずれでも、クラス ファイルが 1 回だけインクルードされることが保証されます。 これらは同じファイル リストを共有するため、混在することを心配する必要はありません。ファイルは以下に含まれています。 require_once()
によって再び含まれることはありません include_once()
.
注記: include_once()
そして require_once()
は関数ではなくステートメントです。 ファイル名を括弧で囲む必要はありません。
同じディレクトリまたはサブディレクトリのコードを含める場合は、ファイル パスを「.」で始めます。include_once ./includes/mymodule_formatting.inc
Drupal 7.x 以降のバージョンでは、DRUPAL_ROOT を使用します。require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc');
モジュールにコードを含めるには:
module_load_include('inc', 'node', 'node.admin');
PHPコードタグ
常に使用する <?php ?>
PHP コードを短縮表記ではなく区切るために、 <? ?>
。 これは Drupal への準拠に必要であり、さまざまなオペレーティング システムやセットアップに PHP コードを組み込むための最も移植性の高い方法でもあります。
Drupal 4.7 の時点では、 ?>
コードファイルの末尾の は意図的に省略されています。 これには、モジュールおよびインクルード ファイルが含まれます。 この理由は次のように要約できます。
- これを削除すると、「ヘッダーはすでに送信されました」エラー、XHTML/XML 検証の問題、その他の問題を引き起こす可能性があるファイルの末尾に不要な空白が存在する可能性がなくなります。
- です ファイルの終わりの終了区切り文字はオプション 。
- PHP.net 自体はファイルの末尾から終了区切り文字を削除するため (例: prepend.inc )、これは「ベスト プラクティス」と見なすことができます。
セミコロン
PHP 言語では、ほとんどの行の末尾にセミコロンが必要ですが、コード ブロックの末尾ではセミコロンを省略できます。 Drupal コーディング標準では、コード ブロックの最後であっても、それらが必要です。 特に、1 行の PHP ブロックの場合は次のようになります。
<?php print $tax; ?> -- YES
<?php print $tax ?> -- NO
URLの例
RFC 2606に従って、すべてのサンプル URL には「example.com」を使用してください 。
命名規則
関数と変数
関数の名前は小文字を使用し、単語はアンダースコアで区切る必要があります。 さらに、モジュール間の名前の衝突を避けるために、関数には接頭辞としてグループ化/モジュール名が必要です。
変数には小文字を使用して名前を付ける必要があり、単語は大文字で区切る必要があります (例: $lowerCamelCase
) またはアンダースコアを使用します (例: $snake_case
)。 一貫性を保つこと。 ファイル内でキャメルケースとスネークケースの変数名を混在させないでください。
永続変数
永続変数 (Drupal の variable_get() / variable_set() 関数を使用して定義された変数/設定) は、すべて小文字を使用して名前を付ける必要があり、単語はアンダースコアで区切る必要があります。 モジュール間の名前の衝突を避けるために、グループ化/モジュール名をプレフィックスとして使用する必要があります。
定数
- 定数は常にすべて大文字にし、単語を区切るにはアンダースコアを使用する必要があります。 (これには、次のような事前定義された PHP 定数が含まれます。
TRUE
,FALSE
、 そしてNULL
.) - モジュール定義の定数名には、それを定義するモジュールの大文字のスペルを接頭辞として付ける必要があります。
- Drupal 8 以降では、定数は
const
PHP 言語キーワード (代わりにdefine()
)、パフォーマンスが向上するためです。/** * Indicates that the item should be removed at the next general cache wipe. */ const CACHE_TEMPORARY = -1;
ご了承くださいconst
PHP 式では機能しません。define()
定数を条件付きで定義する場合、または非リテラル値を使用して定義する場合に使用する必要があります。if (!defined('MAINTENANCE_MODE')) { define('MAINTENANCE_MODE', 'error'); }
グローバル変数
グローバル変数を定義する必要がある場合、その名前は単一のアンダースコアで始まり、その後にモジュール/テーマ名と別のアンダースコアが続く必要があります。
クラス
クラスとインターフェイスに関連するすべての標準 (名前付けを含む) については、ここではなく以下のページで説明されています。
ファイル名
すべてのドキュメント ファイルには、Windows システムで簡単に表示できるように、ファイル名拡張子「.txt」を付ける必要があります。 また、そのようなファイルのファイル名はすべて大文字 (たとえば、readme.txt ではなく README.txt) にする必要がありますが、拡張子自体はすべて小文字 (つまり、TXT ではなく txt) にする必要があります。
例: README.txt、INSTALL.txt、TODO.txt、CHANGELOG.txt など。
ヘルパーモジュール
コーディング標準への準拠のレビューを支援するために利用できる、提供されたモジュール/プロジェクトがいくつかあります。
Coder モジュール。Coder Review (レビュー) と Coder Upgrade (コードを更新) の両方が含まれます。 使用するには:
- モジュールをインストールします (他のモジュールと同様)
- ナビゲーション メニューの [コード レビュー] リンクをクリックします。
- 「特定のモジュールの選択」まで下にスクロールします。
- レビューしたいモジュールを選択し、「送信」ボタンをクリックしてください。
ナビゲーションのコード レビュー リンクから開始する代わりに、モジュール管理画面のリンクをクリックして特定のモジュールのコードをレビューすることもできます。
- Dreditor (パッチなどをレビューするための Firefox ブラウザ プラグイン)。 Chrome に Dreditor をインストールする手順。
- PAReview (プロジェクト アプリケーションをレビューするためのスクリプトのセット。コーディング テストを実行します)
- Coder Sniffer (drupal をロードせずにコーディング標準の検証を実行します)
- Grammar Parser モジュールは、コード標準に準拠してコード ファイルを自動的に書き換える方法を提供します。 モジュールも必要になります おそらく、 Grammar Parser UI 。 これらは Drupal 7 でのみ利用可能です。
この記事に関するご質問やご意見などございましたらお問い合わせフォームからお気軽にご連絡ください。