「コーディングスタイル」の版間の差分

提供:MoodleDocs
移動先:案内検索
879行目: 879行目:
* static: 子/呼び出し元クラスの新しいインスタンスを返すメソッドのため
* static: 子/呼び出し元クラスの新しいインスタンスを返すメソッドのため
* self: for methods returning a new instance of the parent/called class.
* self: for methods returning a new instance of the parent/called class.
* self: 親/呼び出し元クラスの新しいインスタンスを返すメソッドのため
* $this: for methods returning the current instance of the class.
* $this: for methods returning the current instance of the class.
* $this:クラスの現在のインスタンスを返すメソッドのため
* void: for methods with a explicit empty "return" statement.
* void: for methods with a explicit empty "return" statement.
* void: 明示的に空の「return」ステートメントを持つメソッドのための


Also, there are some basic rules about how to use those types:
Also, there are some basic rules about how to use those types:

2021年9月9日 (木) 15:03時点における版

概要

作成中です - Mitsuhiro Yoshida (トーク)

範囲

このドキュメントではMoodleコードに取り組む開発者に対する「スタイル」ガイドラインを示します。ここでは純粋にコードレイアウトの構造および私たちがMoodleのために選択にした内容に関して述べます。この仕様の目的は異なる開発者によるコードを検索する際の認知的摩擦を避けることにあります。これは共有規則一覧およびPHPコード書式の期待値により実現します。

特に他で規定がない限り、このコーディングスタイルドキュメントは PSR-12PSR-1の順で従います。

文書化されていない「デファクトMoodleスタンダード」に遭遇した場合、適切に「MDLSITE」で問題を提起した上でこのコーディングスタイルガイドの中に文書化するか、却下して代わりにPSR勧告を採用すべきです。

* 「デファクトMoodleスタンダード」は一般的にMoodleで使用されるコーディングスタイルです。

ゴール

すべての開発プロジェクト、特に多くの開発者が参加するプロジェクトにおいてコーディングスタイルの一貫性は重要なことです。標準的なスタイルでコードを簡単に読んで理解できるようになるため、結果として全体のクオリティの向上に寄与します。

私たちの努力目標要約:

  • 簡単さ
  • 読みやすさ
  • ツールの親切さ (メソッドシグナチャ、定数、IDEツールをサポートするパターン、自動作成メソッド、クラスおよびの定数名の使用)

上のゴールを考慮する場合、それぞれの局面で環境試験および様々なトレードオフのバランスが必要です。

既存の多くのMoodleコードはこれらすべてのガイドラインには従っていない可能性があります - 私たちは発見次第、引き続きコードをアップグレードします。

Moodle APIの利用に関する詳細はコーディングガイドラインをご覧ください。

便利なツール

このガイドに準拠したコードを書くため、あなたにはいくつかの異なるツールが用意されています。

コードチェッカ (eclipse/phpstormとの統合)
https://moodle.org/plugins/view.php?plugin=local_codechecker
Moodle PHPdocチェッカ
https://moodle.org/plugins/local_moodlecheck

両者とも若干チェック方法が異なるため、自分が書いているコードのチェックに両ツールを使用する価値はあります。 この2つの条件を満たすコードを作成できた場合、あなたの作業を確認する人たちと仲良くなれます。

ファイルフォーマッティング

PHPタグ

常に「長い」PHPタグを使用してください。 ただし、ホワイトスペースの問題を避けるため、ファイルの一番最後に閉じタグを含めないでください。

<?php

require('config.php');

インデント

インデントには タブ文字ではない「半角4スペース」を使用してください。ソースコードに新しいタブ文字が入るのを防ぐため、タブをスペースとして扱うようエディタを設定する必要があります。

メインのスクリプトレベルではインデントしないでください:

良い: <?php require('config.php'); $a = required_param('a', PARAM_INT); if ($a > 10) {

   call_some_error($a);

} else {

   do_something_with($a);

}

悪い: <?php

   require('config.php');
   $a = required_param('a', PARAM_INT);
   if ($a > 10) {
       call_some_error($a);
   } else {
       do_something_with($a);
   }

SQLクエリでは特別なインデントを使用しています。詳細はSQLコーディングスタイルをご覧ください。

最大行長

重要なのは読みやすさです。

便利な場合は132文字を目安にしてください。180文字以上はお勧めしません。

例外は/langディレクトリにある文字列ファイルです。$string['id'] = 'value';という行では値を任意の長さの単一の文字列として定義して引用符で囲む必要があります (連結演算子、heredoc、newdoc構文は使用できません)。これによりこれらの文字列ファイルをPHPコードとして含めることなく構文解析して処理できます。

行の折り返し

行を折り返す場合、一般的に以下のルールを適用してください:

  • デフォルトでは半角4スペースでインデントしてください。
  • 制御文の条件または関数/クラスの宣言で行を折り返した場合、それに続く制御文や関数/クラス本文と視覚的に区別するため、さらに4つの半角スペースでインデントしてください。

以下のセクションの例をご覧ください。

行の折り返しコントロール構造

while ($fileinfolevel && $params['component'] === 'user'

       && $params['filearea'] === 'private') {
   $fileinfolevel = $fileinfolevel->get_parent();
   $params = $fileinfolevel->get_params();

}

IF条件文の行の折り返し

特別なことはなく、制御構造のルールが適用されます。 if (($userenrol->timestart && $userenrol->timestart < $limit) ||

       (!$userenrol->timestart && $userenrol->timecreated < $limit)) {
   return false;

}

しかし、1つの制御構造の中にいくつかの条件がある場合、条件を評価するためのヘルパ変数を設定することで読みやすさが向上します。 $iscourseorcategoryitem = ($element['object']->is_course_item() || $element['object']->is_category_item()); $usesscaleorvalue = in_array($element['object']->gradetype, [GRADE_TYPE_SCALE, GRADE_TYPE_VALUE]);

if ($iscourseorcategoryitem && $usesscaleorvalue) {

   // これにより条件の確認および理解が容易になります。

}

次と比較してください。 // これはしないでください。 if (($element['object']->is_course_item() || $element['object']->is_category_item())

       && ($element['object']->gradetype == GRADE_TYPE_SCALE
       || $element['object']->gradetype == GRADE_TYPE_VALUE)) {
   // 複雑な条件の長すぎる行は適切にインデントされたとしても敬遠されます。

}

クラス宣言の折り返し

class foo implements bar, baz, qux, quux, quuz, corge, grault,

       garply, waldo, fred, plugh, xyzzy, thud {
   // Class body indented with 4 spaces.
   // クラス本体は半角4スペースでインデントします。

}

また、あなたが読みやすさを考慮する場合、それぞれ実装されているインターフェイスを1行にまとめてもよいでしょう:

class provider implements

       // これらの行はクラス本体と視覚的に区別するため、半角8スペースでインデントされています。
       \core_privacy\local\metadata\provider,
       \core_privacy\local\request\subsystem\provider,
       \core_privacy\local\request\core_userlist_provider {
   // クラス本文は半角4スペースでインデントします。

}

関数シグナチャの折り返し

/**

* ...
*/

protected function component_class_callback_failed(\Throwable $e, string $component, string $interface,

       string $methodname, array $params) {
   global $CFG, $DB;
   if ($this->observer) {
       // ...
   }

}

関数呼び出しパラメータの折り返し

通常、パラメータは1行に収まるようになっています。しかし、長過ぎて1行に収まらない場合、または読みやすくしたい場合、半角スペース4個でインデントしてください。

do_something($param1, $param2, null, null,

   $param5, null, true);

配列での折り返し

特別なことはなく、再度一般的なルールが適用されます。折り返し行を半角スペース4個でインデントしてください。 $plugininfo['preferences'][$plugin] = ['id' => $plugin, 'link' => $pref_url,

   'string' => $modulenamestr];

多くの場合、以下のようにぞれぞれの項目を一行にまとめたスタイルの方がコードが読みやすくなります。

$plugininfo['preferences'][$plugin] = [

   'id' => $plugin, 
   'link' => $pref_url, 
   'string' => $modulenamestr,

]; 最後の項目には末尾にカンマが残っていることに注意してください。これにより後で項目のリストを拡張して、よりきれいな差分を取れます。また、同じ理由で代入演算子は揃えない方が良いでしょう。

関数のパラメータとして渡された配列の折り返し

これは上のいくつかの例を組み合わせた例に過ぎません。 $url = new moodle_url('/course/loginas.php', [

   'id' => $course->id,
   'sesskey' => sesskey(),

]);

行の終端処理

標準的な「Unix」テキストフォーマットを使用してください。行末はラインフィード (LF) のみ使用できます。改行は序数10または16進数0x0Aで表されます。

古いマッキントッシュコンピュータのようにキャリッジリターン (CR) を使用しないでください (0x0D)。

Windowsコンピュータのようにキャリッジリターンとラインフィードの組み合わせ (CRLF) を使用しないでください (0x0D, 0x0A)。

行の最後にはスペースを入れないでください。この規則を守るため、ほとんどのエディタでは保存時等に末尾のスペースを削除するよう設定できます。

しかし、あなたが既存のMoodleファイルを編集しながら統合のために変更を適用しようとしている場合、空白の変更がパッチを汚染しないようにこの機能を無効にしてください (すべての行が空白のために編集されている場合、他の開発者はあなたの作業を確認しづらくなります)。

命名規則

ファイル名

ファイル名は:

  • すべて英語にしてください。
  • 可能な限り短くしてください。
  • 英語小文字のみ使用してください。
  • 次の拡張子で終えてください: .php, .html, .js, .css, .xml

クラス

クラス名は常に半角小文字の英語を使用してください。また、アンダースコアで区切ってください。

class some_custom_class {

   function class_method() {
       echo 'foo';
   }

}

コンストラクタがパラメータを必要としない場合でも、新しいインスタンスの作成時には必ず () を使用してください。

$instance = new some_custom_class();

例えば、$DB->insert_recordでデータベースに挿入するデータを用意する場合等、 特定のクラスを持たないプレーンなオブジェクトが必要な場合、 PHPの標準クラス「stdClass」を使用してください。例えば以下のようになります:

$row = new stdClass(); $row->id = $id; $row->field = 'something'; $DB->insert_record('table', $row);

Moodle 2.0以前ではstdClassを拡張したクラス「object」を定義してnew object()を使用していました。これは廃止されたため、代わりにstdClassを使用してください。

関数およびメソッド

関数名はシンプルな英語の小文字およびプラグイン間の衝突を避けるためフランケンスタイルの接頭辞およびプラグイン名で始めてください。単語はアンダースコアで区切ってください。

冗長の推奨: 関数名は理解を深めるために実用的な範囲の例示を推奨します。

PHPではすべての新しいコードにおいて可能な限りすべての場所でタイプヒントおよび戻り値の型の宣言の使用が必要です。ただし、既存の非準拠のコードを拡張するコード、使用できないものを実装する場合等、必要な除外事項もあります。段階的なアプローチが適用されます。

関数名とそれに続く (括弧) の間にはスペースがないことに注意してください。また、ヌル文字 (クエスチョンマーク - ?) およびパラメータまたは戻り値の型の間、関数の閉じ括弧およびコロンの間にも空白はありません。

function report_participation_get_overviews(string $action, ?int userid): ?array {

   // 実際の関数のコードをここに記述します。

}

ただし、活動モジュールのようにレガシーな理由でプラグイン名のみを接頭辞として使用しているものは除きます。

function forum_set_display_mode($mode = 0) {

   global $USER, $CFG;
        
   // 実際の関数のコードをここに記述します。

}

関数パラメータ

パラメータには常にシンプルな小文字の英単語 ($initialvalueのように複数の場合もあります) を使用してください。また、可能であれば常に適切なデフォルト値を持つべきです。

このようにデフォルト値が必要ではない場合、「false」の代わりに「null」を使用してください。 public function foo($required, $optional = null)

ただし、オプションパラメータがbooleanであり、その論理的なデフォルト値が「true」または「false」であるべき場合、「true」または「false」を使用できます。

変数

変数名は常に読みやすく、意味のある小文字の英単語にしてください。どうしても2つ以上の単語が必要な場合、それらをまとめて使用できますが、できるだけ短くしてください。オブジェクトの配列には「複数」名を使用してください。また、常に正の変数名を使用してください(使用可:「enable」、使用不可:「prevent」「disable」)。

良い: $quiz
良い: $errorstring
良い: $assignments (for an array of objects)
良い: $i (but only in little loops)
良い: $allowfilelocking = false
悪い: $Quiz
悪い: $camelCase
悪い: $aReallyLongVariableNameWithoutAGoodReason
悪い: $error_string
悪い: $preventfilelocking = true

Moodleのコアグローバル変数は英語の大文字の変数で識別されます (例 $CFG, $SESSION, $USER, $COURSE, $SITE, $PAGE, $DBおよび$THEME)。これ以上作成しないでください!

定数

定数は常に大文字およびフランケンスタイルの接頭辞およびプラグイン名で始めてください (活動の場合、レガシーな理由でモジュール名のみ)。単語はアンダースコアで区切ってください。

define('BLOCK_COURSE_OVERVIEW_SHOWCATEGORIES_NONE', '0'); define('FORUM_MODE_FLATOLDEST', 1);

ブール値およびヌル値

truefalsenullには小文字を使用してください。

ネームスペース

Moodleのすべての新しいクラスには正式なネームスペースが必要です。以下の例外があります:

  1. 既存の非ネームスペースクラスをネームスペースに移行する必要はありません。
  2. クラスを読み込むための既存のメカニズムが存在、そして、そのメカニズムが名前付きクラスの使用をサポートしていない場合、クラス名に既存のフランケンスタイル接頭辞の付加が許可されます。

クラス名でのクラス名のフランケンスタイル接頭辞の使用は非推奨であり、前述の例外にのみ使用すべきです。

良い: namespace mod_forum; class example { }

namespace mod_forum\external; class example { }

namespace core_user; class example {}

悪い (廃止): class mod_forum_example { }

class mod_forum_external_example { }

class core_user_example { }

ネームスペースの使用は、以下のルールに準拠する必要があります:

  1. ネームスペースに属するクラスはプラグイン内のclassesディレクトリ (mod/forum/classes等) またはコアコードの場合はlib/classesまたはsubsystemdir/classesに作成する必要があります。
  2. すべてのネームスペースクラスのクラス名およびファイル名は自動クラス読み込みのルールに従う必要があります。すべての新しいコードではPHPの正式なネームスペースクラスの使用が必要です。
  3. ファイルごとに最大1つのネームスペース宣言を使用してください。

良い: <? // This is a file mod/porridge/classes/local/equipment/spoon.php

namespace mod_porridge\local\equipment;

class spoon {

   // あなたのコードをここに記述します。

}

// End of file.

悪い: namespace mod_porridge\local\equipment;

class spoon {

   // あなたのコードをここに記述します。

}

namespace mod_porridge\local\procedures; // 私たちはここでネームスペースを変更します。これはやめてください。

class eat {

   // 別のコードをここに記載します。

}

// End of file.

ネームスペース宣言の前にはdocブロックを付加できます。

クラスネーミングルールはそれぞれのレベルのネームスペースにも適用されます。

ネームスペース宣言はファイルの先頭の非コメント行に記述してください。その後、1行の空行、(任意の) 「use」ステートメントが続きます。 「use 」ステートメントは1行に1つずつ記述して、その後に空行を1行記述してください。

コードの中で長いネームスペースが繰り返されないように「use」ステートメントを使用する必要があります。

「use」ステートメントでネームスペース全体をインポートするのではなく、個々のクラスのみをインポートしてください。

衝突を回避するため、絶対に必要な場合を除き名前付きインポート (「XXXXをYYYとして使用」) を使用しないでください。

良い:

use mod_porridge\local\equipment\spoon; // 1行あたり1クラス use mod_porridge\local\equipment\bowl; // 1行あたり1クラス

悪い:

use mod_porridge\local\equipment\spoon, mod_porridge\local\equipment\bowl; // 1行あたり複数クラス use mod_porridge\local; // ネームスペース全体をインポートする use core; // ネームスペース全体をインポートする use mod_breakfast; // ネームスペース全体をインポートする use mod_porridge\local\equipment\spoon as silverspoon; // 理由のない名前付きインポート

the __NAMESPACE__ magic定数は使用しないでください。

「namespace」キーワードはネームスペース宣言以外では使用しないでください。

悪い: $obj = new namespace\Another();

括弧付きの「namespace」ブロックは使用しないでください。

悪い: namespace {

   // Global scope.

}

ネームスペースは「classes」のサブフォルダに存在するクラスにのみ使用する必要があります。

新しいクラスの場合 - ネームスペースの決定時に最大レベルの詳細を使用する必要があります。

良い: namespace xxxx\yyyy; // 「xxxx」はコンポーネント、「yyyy」はapiです。

class zzzz { }

「namespace」および「use」の記述では先頭にバックスラッシュ (/) を使用しないでください。

ネームスペースのコードから呼び出されるグローバル関数には先頭にバックスラッシュ (\) を使用しないでください。

現在のスコープの外にあるクラスは先頭のバックスラッシュを使用してください。そうでない場合、「use」キーワードでインポートされます。詳細はPHPマニュアルを参照してください。

良い: namespace mod_breakfast\local;

use moodle_url;

echo get_string('goodmorning', 'mod_breakfast'); // グローバル関数の先頭にはバックスラッシュを付けないでください。 $url = new moodle_url(...); //「use」でネームスペースにインポートしたため、ここでは先頭のバックスラッシュは必要ではありません。 $tasks = \core\task\manager::get_all_scheduled_tasks(); // ここでは先頭のバックスラッシュが必要です。 $a = new \stdClass(); // ここでは先頭のバックスラッシュが必要です。

悪い: namespace \mod_breakfast; // ここでは先頭のバックスラッシュは不要です。

use \core\task\manager; // ここでは先頭のバックスラッシュは不要です。

\get_string('xxxx', 'yyyy'); // ここでは先頭のバックスラッシュは不要です。

ネームスペースのパーツ

以下のようなクラスの完全修飾名が与えられます:

"\<level1>\<level2>\<level3>\...\<classname>"

ネームスペースの各レベルで何が許されるのか、明確なルールがあります。第一階層のみ必須です。入れ子になったネームスペースはクラスが何らかのコアAPIを実装している場合やプラグインのメンテナがプラグイン内でクラスを別のネームスペースに整理したい場合に使用されます。詳細はレベル2に関するルールをご覧ください。

レベル1のルール

最初のレベルは以下のいずれかでなければなりません:

  • 完全なコンポーネント名 (例: \mod_forum)。プラグインでネームスペースを使用するすべてのクラスはこのレベル1のネームスペースに含まれなければなりません。

または

  • すべてのコアAPIのための"\core"

レベル2のルール

2番目のレベルは以下のいずれかでなければなりません:

または

  • "\local"はメインテナがさらに整理したい場合のクラスコンポーネント内の他のすべてのクラス用です (恐らく、ほとんどのコンポーネントではルートレベル1のネームスペースのみの自クラスで十分です)。

レベル3のルール

レベル3のネームスペースとして使用できるものを制限する規則はありません。ここではプラグインまたはアドオンが他のプラグインまたはAPIと衝突することなく、ネームスペースを広範囲に使用できます。今後も同様に使用できます。

**/testsディレクトリ内のネームスペース

(agreed @ MDLSITE-4800)

  • テストの際にはネームスペースの使用が推奨されます。そして、テスト済み/カバー済みコードのネームスペースと一致させるのが刺激的な方法です。
  • 第1レベルのネームスペースは属するコンポーネントと100%一致します。
  • サブネームスペースは許可されていますが、前述のレベル2および3の一般的なネームスペースのルールに厳密に従っています。

良い: namespace mod_breakfast; // ネストしたネームスペース を使用していない場合のプラグイン独自のネームスペース (典型的なもの) namespace mod_breakfast\local; // ネストしたネームスペース を使用する際のプラグイン自身のネームスペース namespace mod_breakfast\local\utils; // ネストしたネームスペース をさらに整理して使用する場合のプラグインの独自のネームスペース namespace mod_breakfast\event; // コアAPIを実装するためのプラグインのネームスペース

悪い: namespace mymodule; // レベル1のルールに違反 - 無効なコンポーネント名 namespace mod_breakfast\myutilities; // レベル2のルールに違反 - 無効なコアAPI名 namespace mod_forum\test; // 技術的には正しいのですが (「test」は有効なAPIです)、OKではありません。

                                       // なぜなら、テストの名前空間は対象となるコードの名前空間と一致しなければならないため、
                                       // 通常コンポーネントには対象となる「テスト」レベル2は存在しないからです。
                                       // このような場合にのみ使用できます。

ストリング Strings

現在のバージョンのPHPでは文字列のパフォーマンスは問題にならないため、文字列の主な基準は可読性です。

一重引用符 Single quotes

文字列がリテラルである場合や二重引用符を多く含む場合 (HTML等)、常に一重引用符を使用してください:

$a = 'ストリング例'; echo ''; $html = '<a href="http://something" title="something">リンク</a>';

二重引用符

これらはMoodleではあまり役に立たないものです。プレーンな変数や多くの一重引用符を含める必要がある場合、二重引用符 を使用してください。

echo "$string"; $statement = "本気じゃないでしょ!";

複雑なSQLクエリは常に二重引用符で囲む必要があります。

$sql = "SELECT e.*, ue.userid

         FROM {user_enrolments} ue
         JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)
         JOIN {user} u ON u.id = ue.userid
        WHERE :now - u.lastaccess > e.customint2";

変数の置換

変数の置換には以下のような形式があります:

$greeting = "$name さん、おかえりなさい!";

$greeting = "{$name} さん、おかえりなさい!";

文字列の連結

文字列は「.」演算子を使って連結する必要があります。

$longstring = $several.$short.'ストリング';

行が長い場合、複数行に分けて文を読みやすくしてください。このような場合、各行の最後に「ドット (.)」を入れてください。

$string = 'これは非常に長く愚かなストリングです。なぜなら、'.$editorname.
          ' が良い例文を思いつかなかったからです。';

ドット演算子は上の例のように左右にスペースを入れずに使用できます。また、左右にスペースを入れても使用できます。どちらにしても、開発者の好みに合わせて使用できます。

言語ストリング

大文字

言語ストリングは常に次のように記述してください: "Always look like this" そして、次のようには記述しないでください: "Never Like This Example".


大文字は以下の場合のみ使用してください:

  1. 文の始め、または
  2. 「Moodle」のような固有名詞の始め

構造

他の言語で問題が発生する可能性があるため、文字列はUIの連結のために設計されるべきではありません。また、各文字列は独立していなければなりません。

悪い:

$string['overduehandling'] = '受験期限が終了した場合';
$string['overduehandlingautosubmit'] = '受験は自動的に送信されます。';
$string['overduehandlinggraceperiod'] = '受験提出の猶予期間はありますが、それ以上の問題には';
$string['overduehandlingautoabandon'] = '答えられません。時間切れになる前に送信しない場合、カウントされません。';

良い:

$string['overduehandling'] = '時間制限の挙動';
$string['overduehandlingautosubmit'] = '未完了の受験は直ちに送信されます。';
$string['overduehandlinggraceperiod'] = '未完了の受験には評定のための送信猶予期間があります。';
$string['overduehandlingautoabandon'] = '未完了の受験は直ちに破棄されます。';

配列

数値インデックス付き配列

配列を宣言する場合、読みやすさを向上させるため、各コンマ区切りの後にスペースを追加する必要があります:

$myarray = [1, 2, 3, 'Stuff', 'Here'];

複数行のインデックス付き配列でも問題ありませんが、前述のように連続する各行に半角4スペースのインデントを入れてください:

$myarray = [1, 2, 3, 'Stuff', 'Here',

   $a, $b, $c, 56.44, $d, 500];

上の例は以下のようにも記述できることに留意してください:
(注意を引く目的で行末にカンマを付加することにより、後でリスト項目を追加しやすくなります)

$myarray = [

   1, 2, 3, 'Stuff', 'Here',
   $a, $b, $c, 56.44, $d, 500,

];

いずれにしても、1行のアイテム数に関わらず括弧および改行のバランスを取る必要があります。

連想配列

読みやすさを考慮して複数行にも記述できます。例えば以下のようになります:

$myarray = [

   'firstkey' => '最初の値',
   'secondkey' => '2番目の値',

];

クラス宣言

  • クラスはMoodleの命名規則に従って命名する必要があります。
  • 自動読み込みやネームスペーシングの利点を得るため、クラスはそれぞれ「component/classes」ディレクトリ配下に置く必要があります。そこから外に出した場合、そのような贅沢はできません。
  • それぞれのphpファイルには1つのクラス (またはインターフェイスまたはトレイト ...) のみ含みます。ただし、複数のアーティファクトファイルが許可されている古いAPIの一部である場合を除きます。
  • ブレースは常にクラス名の横の行に記述する必要があります。
  • すべてのクラスはPHPDocumentor規格に準拠したドキュメンテーションブロックを持つ必要があります。
  • クラス内のすべてのコードは4つの半角スペースでインデントされる必要があります。
  • クラスファイルでの追加コード ("side-effects") の配置はオートローディングで提供されないアーティファクト (Moodleのブートストラップで読み込まれない「classes」ディレクトリの古いクラスまたはlib) を必要とする場合のみ許可されます。 この場合、MOODLE_INTERNAL checkの使用が必要となります。
例:

/**

* クラスの短い説明です。
*
* クラスの長い説明です (もしあれば) ... 
*
* @package    mod_mymodule
* @copyright  2008 Kim Bloggs
* @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

class sample_class {

   // コンテンツ内のすべてのクラスは
   // 4つの半角スペースでインデントされる必要があります。

} PHPDocスタイルのクラスはこのドキュメントのドキュメンテーションおよびコメント/クラスセクションでより詳細に定義されています。

関数およびメソッド Functions and methods

関数およびメソッド宣言

関数はMoodleの関数命名規則に従って命名する必要があります。

クラス内のメソッドは必ずprivate、protected、publicのいずれかの修飾子を使用して可視性を宣言する必要があります。

クラスと同様にブレスは常に関数名と同じ行に記述する必要があります。

関数名と引数の開始括弧の間にスペースを入れないでください。

戻り値を括弧で囲まないでください。これは可読性を損なうだけでなく、後にメソッドが参照を返すように変更された場合にコードが壊れる可能性があるからです。

Returnは1つのデータタイプのみとします。複数のリターンタイプを持つことは推奨されません。

/**

* ここにドキュメンテーションブロックを置きます。
*/

class sample_class {

   /**
    * ここにドキュメンテーションブロックを置きます。
    */
   public function sample_function() {
       // すべての関数のコンテンツは
       // 半角4スペースでインデントしてください。
       return true;
   }

}

関数およびメソッドの使い方

関数の引数はカンマ区切りの後に半角スペース1つを入れて区切ってください。

three_arguments(1, 2, 3);

マジックメソッド

マジックメソッドは極力避けて、使用する場合は正当な理由が必要となります。注意: 怠慢は有効な議論になりません。

(根拠に関する議論は MDL-52634 をご覧ください)

制御文

一般的に自由に行間のホワイトスペース使用して分かりやすくします。

If / else

括弧内の制御文の前後にスペースを入れて括弧内の半角スペースで演算子を区切ってください。 論理的なグループ化の改善に役立つ場合、内側のブラケットを使用してください。

半角4スペースでインデントしてください。

elseifは使用しないでください!

常に波括弧を使用してください (ブロックが1行でPHPが中括弧を必要としない場合でも)。ブロックの開始波括弧は常に対応する文または宣言と同じ行に置いてください。

if ($x == $y) {

   $a = $b;

} else if ($x == $z) {

   $a = $c;

} else {

   $a = $d;

}

スイッチ

括弧内の制御文の前後にスペースを入れて半角括弧内のスペースで演算子を区切ってください。 論理的なグループ化の改善に役立つ場合、内側のブラケットを使用してください。

常に半角4スペースでインデントしてください。 各ケース制限文の下のコンテンツはさらに4つの半角スペースでインデントする必要があります。

switch ($something) {

   ケース1:
       break;
   ケース2:
       break;
   default:
       break;

}

Foreach

前述のように以下のような形で半角スペースを使用してください:

foreach ($objects as $key => $thing) {

   process($thing);

}

三項演算子

三項演算子は「短く」「わかりやすい」文にのみでの使用が許可されています。一文で理解できない場合、代わりにif文を使用してください。

演算子の周りには空白を設けて、どこで演算しているか明確にする必要があります。

良い例: $username = isset($user->username) ? $user->username : ; ** $users = is_array($users) ? $users : [$users];

悪い例: $toload = (empty($CFG->navshowallcourses))?self::LOAD_ROOT_CATEGORIES:self::LOAD_ALL_CATEGORIES; $coefstring = ($coefstring== or $coefstring=='aggregationcoefextrasum') ? 'aggregationcoefextrasum' : 'aggregationcoef';

** PHP 7.0以降、「isset()」の多くの3値は新しい省略形 null coalescing operator を使用するように変更することができるため、前述の例は以下と同であることに留意してください:

$username = $user->username ?? ;

Require / include

ブラウザからアクセスされる各ファイルに関して、最初にメインのconfig.phpファイルを含むようにしてください。

require(__DIR__ . '/../../config.php');

その他のinclude/requireでは__DIR__え始まるパス、または$CFG->dirrootまたは$CFG->libdirで始まる絶対パスを使用してください。

「../」で始まる相対的なインクルードはPHPで変な動作をすることがあるため使用しないでください。私たちのCLIスクリプトでは「../」で始まる相対的なconfig.phpのパスを使用すべきではありません。

通常の用途で使用するライブラリファイルではrequire_onceを使用してください (これは前述のように常に「require」を使用すべきconfig.phpとは異なります)。例: require_once(__DIR__ . '/locallib.php'); require_once($CFG->libdir . '/filelib.php');

includeは一般的にファイルの先頭またはそれを必要とする関数/メソッド内部でのみ実行されるべきです。グローバルスコープのファイルの途中でinclude/requireを使用した場合、コードのセキュリティ監査が非常に困難になります。

インポートされたサードパーティのライブラリおよび「副作用」のないファイル (単一のクラス定義、インターフェイスまたはトレイト等) を除く他のすべてのスクリプトでは一番上に以下のコードを使用して、間違って設定された本番サーバでエラーメッセージが表示される可能性のある直接実行を防ぐ必要があります。

defined('MOODLE_INTERNAL') || die();

*副作用: グローバルスコープのコードで a)ネームスペースおよびuse文、b)ネームスペースの定数、c)strict_types宣言 (一般的な宣言) ではないもの。

ファイル内の副作用の有無は上で説明したようにコードレベルでのみ影響することに注意してください。特に言及されていない限り、その他のコーディングスタイルにおいては考慮すべきではありません。

ドキュメンテーションおよびコメント Documentation and comments

Code documentation explains the code flow and the purpose of functions and variables. Use it whenever practical. コードドキュメンテーションではコードの流れ、関数および変数の目的を説明します。 実際のコーディングには必ず使用してください。

PHPDoc

Moodle stays as close as possible to "standard" PHPDoc format to document our files, classes and functions. This helps IDEs (like Netbeans or Eclipse) work properly for Moodle developers, and also allows us to generate web documentation automatically. Moodleはファイル、クラスおよび関数をドキュメント化するため、「標準」PHPDocフォーマットにできるだけ近づけています。 これにより (NetbeansまたはEclipseのような) IDEはMoodle開発者のために適切に動作します。また、私たちがウェブドキュメントを自動生成できます。

PHPDoc has a number of tags that can be used in different places (files, classes and functions). We have some particular rules for using them in Moodle that you must follow: PHPDocには様々な場所 (ファイル、クラス、関数) で使用できる多くのタグがあります。 Moodleでそれらのタグを使用するには私たちが従う必要のある個別のルールがあります。

タイプ Types

Some of the tags below (@param, @return...) do require the specification of a valid php type and a description. All these are allowed: 以下のいくつかのタグ (@param, @return...) は有効なPHP型および説明の指定を必要とします。以下、これらすべてが許可されています:

  • PHP primitive types: int, bool, string...
  • PHPプリミティブ型: int, bool, string...
  • PHP complex types: array, stdClass (not Array, object).
  • PHP複合型: 配列, stdClass (非配列、オブジェクト)
  • PHP classes:full or relative (to current namespace) class names.
  • PHPクラス:フルまたは (現在のネームスペースに対して) 相対クラス名
  • true, false, null (always lowercase).
  • true, false, null (常に半角英小文字)
  • static: for methods returning a new instance of the child/caller class.
  • static: 子/呼び出し元クラスの新しいインスタンスを返すメソッドのため
  • self: for methods returning a new instance of the parent/called class.
  • self: 親/呼び出し元クラスの新しいインスタンスを返すメソッドのため
  • $this: for methods returning the current instance of the class.
  • $this:クラスの現在のインスタンスを返すメソッドのため
  • void: for methods with a explicit empty "return" statement.
  • void: 明示的に空の「return」ステートメントを持つメソッドのための

Also, there are some basic rules about how to use those types:

  • We use short type names (bool instead of boolean, int instead of integer).
  • When multiple occurrences of a given "type" are used, it's highly recommended to document them as type[] instead of the simpler and less informative "array" alternative.
  • When multiple different types are possible, they must be separated by a vertical bar (pipe).
  • All primitives and keywords must be lowercase. The case of the complex types and classes must match the original.

Tags

@copyright

These include the year and copyright holder (creator) of the original file. Do not change these in existing files!

 @copyright 2008 Kim Bloggs
@license

These must be GPL v3+ and use this format:

 @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@param

Don't put hyphens or anything fancy after the variable name, just a space.

 @param type $name Description.
@return

The @return tag is mandatory if the function has a return statement, but can be left out if it does not have one.

The description portion is optional, it can be left out if the function is simple and already describes what is returned.

 @return type Description.
@var

The @var tag is used to document class properties.

 @var type Description.

Exceptionally, when none of the available types define the returned value, inline @var phpdocs (within the body of the methods) providing type hinting are allowed to the returned type. Don't abuse!

@uses

If a function uses die or exit, please add this tag to the docblock to help developers know this function could terminate the page:

 @uses exit
@access

The access can be used to specify access control for an element

  1. Should only be used when the method definition does not already specify access control.
  2. In the case of functions, specifying public access is redundant and so should be avoided.
 @access private
@package

The package tag should always be used to label php files with the correct Frankenstyle component name. Full rules are explained on that page, but in summary:

  1. If the file is part of any component plugin, then use the plugin component name (eg mod_quiz or gradereport_xls)
  2. If the file is part of a core subsystem then it will be core_xxxx where xxxx is the name defined in get_core_subsystems(). (eg core_enrol or core_group)
  3. If the file is one of the select few files in core that are not part of a subsystem (such as lib/moodlelib.php) then it just as a package of core.
  4. Each file can only be part of ONE package.

(We do not have standards for @subpackage at all. You can use within your @package how you like.)

 @package gradereport_xls
@category

We use @category only to highlight the public classes, functions or files that are part of one of our Core APIs, or that provide good example implementations of a Core API. The value must be one of the ones on the Core APIs page.

 @category preferences 
@since

When adding a new classes or function to the Moodle core libraries (or adding a new method to an existing class), use a @since tag to document which version of Moodle it was added in. For example:

 @since Moodle 2.1
@see

If you want to refer the user to another related element (include, class, function, define, method, variable), but not to URLs, then you can use @see.

 @see some_other_function()

This tag can be used inline too, within phpdoc comments.

  /**
   * This function uses {@see get_string()} to obtain the currency names...
   * .....
@link

If you want to refer the user to an external URL, but not to related elements, use @link.

 @link https://docs.moodle.org/dev/Core_APIs

This tag can be used inline too, within phpdoc comments.

  /**
   * For details about the implementation below, visit {@link https://docs.moodle.org/dev/Core_APIs} and read...
   * .....
@deprecated (and @todo)

When deprecating an old API, use a @deprecated tag to document which version of Moodle it was deprecated in, and add @todo and @see if possible. Make sure to mention relevant MDL issues. For example:

/**

* ...
* @deprecated since Moodle 2.0 MDL-12345 - please do not use this function any more.   
* @todo MDL-22334 This will be deleted in Moodle 2.2.
* @see class_name::new_function()
*/

If it is important that developers update their code, consider also adding a debugging('...', DEBUG_DEVELOPER); call to repeat the deprecated message. If the old function can no longer be supported at all, you may have to throw a coding_exception. There are examples of the various options in lib/deprecatedlib.php.

@throws

This tag is valid and can be used optionally to indicate the method or function will throw and exception. This is to help developers know they may have to handle the exceptions from such functions.

Other specific tags

There are some tags that are only allowed within some contexts and not globally. More precisely:

  • @Given, @When, @Then, within the behat steps definitions.
  • @covers, @coversDefaultClass, @coversNothing, to better control coverage within unit tests.
  • @dataProvider, within unit tests.
  • @expectedException[Code|Message|MessageRegExp], to define exception expectations, within unit tests. *)
  • @group, for easier collecting unit tests together, following the guidelines in the PHPUnit MoodleDocs.
  • @codingStandardsIgnoreLine, to allow next line to be skipped by the Codechecker (phpcs).

*) Please note that current best practice is to use $this->expectException() instead of the annotation syntax.

Files

All files that contain PHP code should contain, without any blank line after the php open tag, a full GPL copyright statement at the top, plus a SEPARATE docblock right under it containing a:

  1. short one-line description of the file
  2. longer description of the file
  3. @package tag (required)
  4. @category tag (only when everything in the file is related to one of the Core APIs)
  5. @copyright (required)
  6. @license (required)

For files containing only one artifact, the file phpdc block is optional as long as the artifact (class, interface, trait...) is documented. Read the following "Classes" section about that case.

<?php // This file is part of Moodle - https://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <https://www.gnu.org/licenses/>.

/**

* This is a one-line short description of the file.
*
* You can have a rather longer description of the file as well,
* if you like, and it can span multiple lines.
*
* @package    mod_mymodule
* @category   backup
* @copyright  2008 Kim Bloggs
* @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

Classes

All classes must have a complete docblock like this:

/**

* Short description for class.
*
* Long description for class (if any)...
*
* @package    mod_mymodule
* @category   backup
* @copyright  2008 Kim Bloggs
* @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

class policy_issue {

For files containing only one artifact (class, interface, trait...), specifically for all the files within classes directories, but also any other file fulfilling the condition anywhere else, it will be enough with the class phpdoc block. The file phpdoc block will be considered optional at all effects, giving to the class one precedence.

The @package, @copyright and @license tags (and the optional @category tag ), as shown in the example above, must be present always in the file (in whichever docblock, but all together).

Properties

All properties should have a docblock with the following minimum information:

class example {

   /** @var string This variable does something */
   protected $something;

} or class example {

   /** 
    * This variable does something and has a very long description which can
    * wrap on multiple lines
    * @var string 
    */
   protected $something;

} Even if there are several properties all sharing something in common, do not use DocBlock templates. Instead, document every property explicitly as in the following example:

class zebra {

   /** @var int The number of white stripes */
   protected $whitestripes = 0;
   /** @var int The number of black stripes */
   protected $blackstripes = 0;
   /** @var int The number of red stripes */
   protected $redstripes = 0;

}

Constants

Class constants should be documented in the following way:

class sam {

  /**
   * This is used when Sam is in a good mood.
   */
  const MOOD_GOOD = 0;

}


Functions

All functions and methods should have a complete docblock like this:

/**

* The description should be first, with asterisks laid out exactly
* like this example. If you want to refer to a another function,
* use @see as below.   If it's useful to link to Moodle
* documentation on the web, you can use a @link below or also 
* inline like this {@link https://docs.moodle.org/dev/something}
* Then, add descriptions for each parameter and the return value as follows.
*
* @see clean_param()
* @param int   $postid The PHP type is followed by the variable name
* @param array $scale The PHP type is followed by the variable name
* @param array $ratings The PHP type is followed by the variable name
* @return bool A status indicating success or failure
*/

You must include a description even if it appears to be obvious from the @param and/or @return lines.

An exception is made for overridden methods which make no change to the meaning of the parent method and maintain the same arguments/return values. In this case you should omit the comment completely. Use of the @inheritdoc or @see tags is explicitly forbidden as a replacement for any complete docblock.

Defines

All defines should be documented in the following way:

/**

* PARAM_INT - integers only, use when expecting only numbers.
*/

define('PARAM_INT', 'int');

/**

* PARAM_ALPHANUM - expected numbers and letters only.
*/

define('PARAM_ALPHANUM', 'alphanum');

Inline comments

Inline comments must use the "// " (2 slashes + whitespace) style, laid out neatly so that it fits among the code and lines up with it. The first line of the comment must begin with a capital letter (or a digit, or '...') and the comment must end with a proper punctuation character. Permitted final characters are '.', '?' or '!'.

function forum_get_ratings_mean($postid, $scale, $ratings = null) {

   if (!$ratings) {
       $ratings = [];     // Initialize the empty array.
       $rates = $DB->get_records('forum_ratings', ['post' => $postid)];
       // ... then process each rating in
       // turn.
       foreach ($rates as $rate) {
           do_something_with($rate);
       }
       // Do we need to tidy up?
       if (!empty($rates))
           // 42 more things happen here!
           finsh_up();
       }

GOOD: // Comment explaining this piece of code. BAD: /* Comment explaining this piece of code. */

  1. Comment explaining this piece of code.

// comment explaining this piece of code (without capital letter and punctuation)


If your comment is due to some MDL issue, please feel free to include the correct MDL-12345 in your comment. This makes it easier to track down decisions and discussions about things.

Using TODO

This is especially important if you know an issue still exists in that code that should be dealt with later. Use a TODO along with a MDL code to mark this. For example:

// TODO MDL-12345 This works but is a bit of a hack and should be revised in future.

If you have a big task that is nearly done, apart a few TODOs, and you really want to mark the big task as finished, then you should file new tracker tasks for each TODO and change the TODOs comments to point at the new issue numbers.

There is a nice "todo checker" reporting tool, restricted to admins and available via web @ lib/tests/other/todochecker.php.

Finally, don't forget to add any MDL-l2345 used by your TODOs (and @todos too, unless part of the deprecation process, those are handled apart) to the "Review TODOs Epic" : MDL-47779 (requires login to see the issues)

CVS keywords

We have stopped using CVS keywords such as $Id$ in Moodle 2.0 completely.

Exceptions

Use exceptions to report errors, especially in library code.

Throwing an exception has almost exactly the same effect as calling print_error(), but it is more flexible. For example, the caller can choose to catch the exception and handle it in some way. It also makes it easier to write unit tests.

Note that, since 2021, it has been agreed to deprecate print_error() and, instead, to throw moodle_exception() is the correct way to proceed.

Any exception that is not caught will trigger an appropriate call to print_error, to report the problem to the user. Exceptions "error codes" will be translated only when they are meant to be shown to final users.

Do not abuse exceptions for normal code flow. Exceptions should only be used in erroneous situations.

Exception classes

We have a set of custom exception classes. The base class is moodle_exception. You will see that the arguments you pass to new moodle_exception(...) are very similar to the ones you would pass to print_error. There are more specific subclasses for particular types of error.

To get the full list of exception types, search for the regular expression 'class +\w+_exception +extends' or ask your IDE to list all the subclasses of moodle_exception.

Where appropriate, you should create new subclasses of moodle_exception for use in your code.

A few notable exception types:

moodle_exception
base class for exceptions in Moodle. Use this when a more specific type is not appropriate.
coding_exception
thrown when the problem seems to be caused by a developer's mistake. Often thrown by core code that interacts with plugins. If you throw an exception of this type, try to make the error message helpful to the plugin author, so they know how to fix their code.
dml_exception (and subclasses)
thrown when a database query fails.
file_exception
thrown by the File API.

Dangerous functions and constructs

PHP includes multiple questionable features that are highly discouraged because they are very often source of serious security problems.

  1. do not use eval() function - language packs are exception (to be solved in future).
  2. do not use preg_replace() with /e modifier - use callbacks in order to prevent unintended PHP execution.
  3. do not use backticks for shell command execution.
  4. do not use goto, neither the operator neither labels - use other programming techniques to control the execution flow.

Policy about coding-style only fixes

Way before this coding-style guide was defined and agreed, a lot of code had been written already. Obviously such code does not follow the coding-style at all. While we enforce conformance for all the new code, we are not paranoid about the status of all the previous one.

In any case, in order to normalize the (progressive, non-critical) transition, a policy issue (MDL-43233) was created and agreed about. And these are the rules to apply to coding-style only changes:

  1. Related coding-style changes (same lines, a variable within a method/function, adjacent comments...) within a real issue are allowed.
  2. Unrelated coding-style changes (other methods, blocks of code, comments...) within a real issue are only accepted for master and in a separate commit.
  3. Coding-style only issues are only accepted for master along the first 2 months of every cycle.

Git commits

Constructing a clear and informative commit is an important aspect of the craft of creating open source code and the history of commits is a vital part of the communication between developers. Time should be spent on crafting commits appropriately and using the git tools to achieve it.

Git commits should:

  • Tell a perfect, cleaned up version of the history. As if the code was written perfectly first time.
  • Include the MDL-xxxx issue number associated with the change
  • Include CODE AREA when appropriate. (Code area, is just a short name for the area of Moodle that this change affects. It can be a component name if that makes sense, but does not have to be. Remember that your audience here is humans not computers, so if a shortened version of a component name is more readable and distinctive, use that instead.)
  • Be formatted as:
MDL-xxxx CODE AREA: short summary (72 chars soft limit)

Blank line on line 2, followed by an unlimited length detailed explanation
following if necessary. This section might include the motivation for the change
and contrast it with the previous behaviour.

Git commits should not:

  • Include changes from bugs found and fixed before integration
  • Include many separate revisions to the same lines of code for a single issue
  • Arbitrarily split when part of a atomic set of logical changes

For more guidance, see Commit cheat sheet

Credits

This document was drawn from the following sources:

  1. The original Coding guidelines page
  2. The Zend guidelines and
  3. Feedback from all core Moodle developers

関連情報