Open main menu

Manual:コーディング規約

This page is a translated version of the page Manual:Coding conventions and the translation is 97% complete.

Other languages:
English • ‎dansk • ‎español • ‎français • ‎polski • ‎português • ‎português do Brasil • ‎čeština • ‎русский • ‎العربية • ‎تۆرکجه • ‎සිංහල • ‎中文 • ‎日本語
ショートカット: CC

このページでは、MediaWiki コードベース内や、ウィキメディアのウェブサイト群で使用されることを意図している拡張機能内で使用される、コーディング規約を説明します。 コードレビューワーは、これら規約に従わない変更をまとめて-1処理することがあります。その場合は、スタイルの問題を修正してパッチを更新するように推奨されたと解釈するようにお願いします。

このページでは、コードがどの言語で書かれているかにかかわらずすべての MediaWiki コードに適用される全般的な規約を列挙します。 MediaWiki の特定のコンポーネントやファイルの種類に適用されるガイドラインについては、以下を参照してください:

wiki技術部 (少なくとも運営/パペットに適用):

コードの構造

ファイルの整形

タブの幅

各行は深さ1段ごとにタブ記号1個でインデントを施します。タブ1個が何文字相当か自分で決めることはできません。MediaWikiの開発者の多くは可読性の面からもタブ1個を半角アキ4個相当が妥当だとしていますが、多くのシステムでは半角アキ8個相当の設定で、なかには半角アキ2個のつもりで使用する開発者もいます。

テキストエディタのvim利用者には$HOME/.vimrcに以下の記述を追加して設定する方法があります。

autocmd Filetype php setlocal ts=4 sw=4

CSSやHTML、JavaScriptにも似た記述を使います。

しかしながらPythonでは、コードのスタイルガイドPEP 8の空白スペース (アキ) ガイドラインに従い、タブではなくアキを使用するように推奨しています。

改行

どのファイルも改行はUnix式にします (LF記号1個であって、CR+LFではない)。

  • Windows版のgitでは (既定として) コミットの段階で自動的にCR+LF改行をLFに置換します。

すべてのファイルについて、末尾に改行文字を付けるべきです。

  • その他の行はすべて、行末に改行記号があるため整合性があります。
  • これにより非バイナリ形式 (差分など) でのデータ取り回しが楽になります。
  • catwcなどコマンドラインツールで欠如するとファイル処理が円滑に進みません (あるいは少なくとも予期したりこうあるべきと思う挙動になりません)。

エンコーディング

テキストファイルはすべてBOMのない、UTF-8で符号化。

ファイル編集には、必ずBOMを挿入するMicrosoft Notepadは使用できません。 ファイル冒頭に特殊文字BOMが入ることによって、ウェブブラウザがそれをクライアントに出力するため、PHPファイルの作動が阻害されます。

まとめるなら、必ずUTF-8対応でBOMを挿入しないエディタをご利用ください。

末尾の空白類

IDEを使用すると「Home」と「End」のキー (その他のキーボードショートカットも含む) を押すと、想定どおり、通常は行末の空白スペースを無視してコード末尾にジャンプします。ところが非IDEテキストエディタの場合は「End」キーを押すと行末の空白スペースの末尾に飛んでしまい、開発者は入力しようとして想定した位置まで、バックスペースで戻る必要があります。

操作としては、行末の空白スペースの削除はほとんどのテキストエディタで簡単です。開発者は、他の可視コードを含む行では特に、行の末尾に空白を入れないでください。

処理を簡略化するツールがあります。

  • nano: GNU nano 3.2;
  • Komodo Edit : メニューの「Edit > Preferences」を開きSave Optionsで「Clean trailing whitespace and EOL markers」ならびに「Only clean changed lines」を有効にする;
  • Kate: オプション「Highlight trailing spaces」を有効にすると、行末の空白スペースを表示する。「Settings > Configure Kate > Appearance」から設定。また「Settings > Configure Kate > Open/Save」の設定で、保存時に行末の空白スペース削除を自動処理できる。
  • vim: さまざまな自動クリーンナッププラグインを備える。
  • Sublime Text: TrailingSpace処理用プラグイン (行末の空白スペースを強調表示、削除)

キーワード

キーワード (例 require_oncerequire) に不要な括弧を付けない。

インデントと配置

全般的なスタイル

MediaWikiのインデントの形式は、いわゆる字下げスタイルの1TBS あるいは OTBSと同様です。波括弧は関数、条件文やループなどの開始と同じ行に置きます。else/elseifは直前の「閉じる」波括弧と同じ行に置きます。

function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) {
    if ( $ts === null ) {
        return null;
    } else {
        return wfTimestamp( $outputtype, $ts );
    }
}

複数行にわたる文の場合、2行目以降の行を1段深くインデントして記述します。

インデントと改行を使い、コードの論理的構造を明示します。インデントの深さを変え入れ子にした複数の波括弧あるいは同様の構造にすると、入れ子構造ごとに新しいインデントを作る場合があります。

$wgAutopromote = [
    'autoconfirmed' => [ '&',
        [ APCOND_EDITCOUNT, &$wgAutoConfirmCount ],
        [ APCOND_AGE, &$wgAutoConfirmAge ],
    ],
];

switch文では波括弧のセット内とケースにインデントを次のように用います。

switch ( $word ) {
    case 'lorem':
    case 'ipsum':
        $bar = 2;
        break;
    case 'dolor':
        $bar = 3;
        break;
    default:
        $bar = 0;
        break;
}

垂直方向の位置合わせ

垂直方向の配置の使用は避けます。新しい項目を追加するたび、左カラムに適用する幅を増やす必要があり、差分表示が読み取りにくくなります。

差分表示ツールの多くには空白スペースの変更を無視するオプションがあります。
Git: git diff -w

必要に応じて、行中心で垂直位置合わせをするには、タブではなく空白スペースを使います。例はこうなります。

$namespaceNames = [
    NS_MEDIA            => 'Media',
    NS_SPECIAL          => 'Special',
    NS_MAIN             => '',
];

これは空白スペースが半角中グロ「・」に変換され、下記の表示になります。

$namespaceNames·=·[
 →  NS_MEDIA············=>·'Media',
 →  NS_SPECIAL··········=>·'Special',
 →  NS_MAIN·············=>·'',
];

(もしvimでアドオンtabular vim add-onを使用した場合、:Tabularize /=と入力すると「=」符号の場所で位置合わせします。)

行の継続

1行は80桁から100桁の範囲で改行します。特殊な例外はありますが、多数のパラメータを採用する関数は例外なく改行が必要です。

The operator separating the two lines should be placed consistently (always at the end or always at the start of the line). Individual languages might have more specific rules.

return strtolower( $val ) === 'on'
    || strtolower( $val ) === 'true'
    || strtolower( $val ) === 'yes'
    || preg_match( '/^\s*[+-]?0*[1-9]/', $val );
$foo->dobar(
    Xml::fieldset( wfMessage( 'importinterwiki' )->text() ) .
        Xml::openElement( 'form', [ 'method' => 'post', 'action' => $action, 'id' => 'mw-import-interwiki-form' ] ) .
        wfMessage( 'import-interwiki-text' )->parse() .
        Xml::hidden( 'action', 'submit' ) .
        Xml::hidden( 'source', 'interwiki' ) .
        Xml::hidden( 'editToken', $wgUser->editToken() ),
    'secondArgument'
);

The method operator should always be put at the beginning of the next line.

$this->getMockBuilder( Message::class )->setMethods( [ 'fetchMessage' ] )
    ->disableOriginalConstructor()
    ->getMock();

「if」文が続くときは、オールマンのスタイル 括弧に置換して制御文と本文の区分を明示します。

if ( $.inArray( mw.config.get( 'wgNamespaceNumber' ), whitelistedNamespaces ) !== -1 &&
    mw.config.get( 'wgArticleId' ) > 0 &&
    ( mw.config.get( 'wgAction' ) == 'view' || mw.config.get( 'wgAction' ) == 'purge' ) &&
    mw.util.getParamValue( 'redirect' ) !== 'no' &&
    mw.util.getParamValue( 'printable' ) !== 'yes'
) {
    ..
}

制御文を区分するために必要なインデントの深さについては意見が分かれています。本文とは異なるインデントの深さにすると、制御文の部分が本文と異なることを明示するものの、ユニバーサルな解釈ではありません。

制御文が継続して表現が長大になると、どちらの方法を使っても見た目は美しくなりません。いずれにしても最善策として、一時的な変数を使い、複数行に分割します。

波括弧で囲まない制御構造

「ブロック」は1行に記述しない。左マージンから読者が探すはずの重要な文を、遠い位置に動かしてしまう結果になるためです。コードを短くしても簡略化したことになりません。コーディングの形式はヒトとのコミュニケーションを効率化することにあり、狭い空間にコンピュータ可読の文を押し込むことではありません。

// No:
if ( $done ) return;

// No:
if ( $done ) { return; }

// Yes:
if ( $done ) {
    return;
}

この方法は開発者が「スマートなインデント」機能のないテキストエディタを使用している場合に特に発生しがちな、一般的な論理エラーを回避します。1行だったブロックを後に2行に拡張した場合、このエラーが発生します。

if ( $done )
    return;

上記に後で次の変更を加えた場合。

if ( $done )
    $this->cleanup();
    return;

これにより微妙なバグが発生する可能性があります。

Emacs方式

EmacsではnXHTMLモードに代わってphp-mode.elを使用し、 .emacsファイルにMediaWikiマイナーモードを設定できます。

(defconst mw-style
  '((indent-tabs-mode . t)
    (tab-width . 4)
    (c-basic-offset . 4)
    (c-offsets-alist . ((case-label . +)
                        (arglist-cont-nonempty . +)
                        (arglist-close . 0)
                        (cpp-macro . (lambda(x) (cdr x)))
                        (comment-intro . 0)))
    (c-hanging-braces-alist
        (defun-open after)
        (block-open after)
        (defun-close))))

(c-add-style "MediaWiki" mw-style)

(define-minor-mode mah/mw-mode
  "tweak style for mediawiki"
  nil " MW" nil
  (delete-trailing-whitespace)
  (tabify (point-min) (point-max))
  (subword-mode 1)) ;; If this gives an error, try (c-subword-mode 1)), which is the earlier name for it

;; Add other sniffers as needed
(defun mah/sniff-php-style (filename)
  "Given a filename, provide a cons cell of
   (style-name . function)
where style-name is the style to use and function
sets the minor-mode"
  (cond ((string-match "/\\(mw[^/]*\\|mediawiki\\)/"
                       filename)
         (cons "MediaWiki" 'mah/mw-mode))
        (t
         (cons "cc-mode" (lambda (n) t)))))

(add-hook 'php-mode-hook (lambda () (let ((ans (when (buffer-file-name)
                                                 (mah/sniff-php-style (buffer-file-name)))))
                                      (c-set-style (car ans))
                                      (funcall (cdr ans) 1))))

上記のmah/sniff-php-style関数はパスを確認し、php-modeを呼び出したときに「mw」または「mediawiki」を含んでいるかどうか見極めると、バッファを設定してMediaWikiのソースの編集にmw-modeマイナーモードを使用させます。バッファがmw-modeを使用したことは、モードラインに「PHP MW」や「PHP/lw MW」のようなものが表示されると判断できます。

データ操作

URL の構築

文字列の連結などの方法で手動でURLを構築しないでください。リクエストをコードが行う場合 ( 特にPOSTとバックグラウンドリクエスト) には必ず完全なURL形式を使用します。

PHPで使用できる方式は適切なLinker またはTitle 方式、ウィキテキストではfullurl というマジックワード、JavaScriptを使うならmw.util.getURL()方式、さらに他の言語の同様の方式です。予期せぬ短いURL構成などの問題を避けることができます。

ファイルの命名

サーバ側のコードを含むファイルには要素語の最初を大文字で書き表すアッパーキャメルケースで命名します。拡張機能の命名規約もこの方式です[1]。ファイル内の最も重要なクラスに基づいて命名します。ほとんどのファイルにはクラス1件のみ、もしくはベースクラスと複数のdescendantが含まれます。たとえばTitle.phpに含まれるTitleクラスは1件のみです。WebRequest.phpWebRequestクラスに加えて含まれるFauxRequestおよびDerivativeRequestは両方ともそのdescendantです。

アクセスポイントのファイル

SQLなど「access point」ファイルに命名し、PHPエントリポイントの名前にはindex.phpfoobar.sqlなどのように小文字表記に限定しています。メンテナンスのスクリプトは一般的に小文字のキャメルケースで記述しますが、必ずしもこの限りではありません。サイト管理者が使うファイルでreadme、licensesやchangelogsなどは大文字表記です。

ファイルやディレクトリの名称に空白スペースあるいは非ASCII文字を使わないでください。小文字表記の題名はアンダースコア (_) ではなくハイフン (-) を使うようにします。

JS、CSSとメディアの命名

JavaScript、CSSとメディアのファイル (通常はResourceLoader経由で読み込み) の命名は次の例のようにモジュールの名称と一致させます。

  • mediawiki.fooというモジュールに対応するファイル名はresources/src/mediawiki.foo/bar.jsresources/src/mediawiki.foo/baz.cssがありえます。
  • mediawiki.Titleというモジュールに対応するファイル名はresources/src/mediawiki.Title.jsです。

拡張機能が命名したモジュール名にはext.myExtensionのように名づける決まりで、次のような例があります。

  • extensions/FooBar/resources/ext.fooBar/init.js

この方法であれば、編集の利便上、単一のモジュールを細かく分割したとした後にもう一度ひとつのモジュールにまとめたとしても、ファイルを探すのが容易になります。.

説明文書

言語に特化した下位ページには、ファイル内のコードコメントの構文そのものの情報が、例えばdoxygenに対してはcomments in PHPのコメントに含まれています。 正確な構文を使用すると、http://doc.wikimedia.orgのソースコードから説明文書の生成ができます。

MediaWikiの一部の要素はコアの/docs folderに説明文書があります。例えば新しいフックを追加した場合、そのフックの名称を使って/docs/hooks.txtを更新し、フックの作用とフックが用いるパラメータを記述します。

テキスト ファイル

開発者は解説文書をコードとともにGitに保管できます。 この方法は拡張機能アーキテクチャやデータベース設計でコードのコミットごとに更新が必要な詳しい説明文書に適しています。 Gitに説明文書を置くmediawiki.org上のページは、双方を{{git file}}を使ってリンクします。.

(Gitファイルからテキストをウィキに参照読み込みする可能性phab:T91626で追跡しています。)

多くの技術的説明ページでmediawiki.orgのページに含まれるものは、多数のリリースを重ねたMediaWikiコードの進化の記録でもあります。 変更点は個々の説明文書に記述するか、あるいは 最終版のコードベースに限定して「原本」 (master) に述べます。

テキスト ファイルの書式

.wiki
テキストファイルがウィキ形式であれば、.wiki拡張機能を付与します。 GitHubはウィキテキストの部分集合を解析することができるので、GitHubにミラーリングされた"foo".wikiファイルはいくつかの書式設定を表示します (.mediawiki拡張機能でも可能ですが時間がかかります)。 例えばウィキベース拡張機能のdocs/lua.wikiGitHubにあります。


.md
DoxygenMarkdown書式設定をサポートしており、ドキュメントを軽くフォーマットして.mdファイルに置くことができます。DiffusionとGitHubも.mdファイルをサポートしています。ディレクトリやプロジェクトの解説ファイルはREADME.mdと命名します; DiffusionとGitHubはディレクトリあるいはプロジェクトを閲覧するとこのファイルを表示します (例:DiffusionGitHub上のRESTbaseのdoc/development/)。
拡張子のない.txtファイル
Doxygenは既定でこれらをC言語のファイル(!!、タスク T106116で追跡)として解析します。これを利用するには、ファイルにCコメントを模倣させてから、doxygenディレクティブをファイルに追加します。例えばincludes/filebackend/READMEdoxygenにファイルのバックエンドデザインを生成し、冒頭は以下のとおりです。
/*!
\ingroup FileBackend
\page file_backend_design File backend design

Some notes on the FileBackend architecture.
...
Special:Version/CreditsAUTHORSCREDITS(拡張子なし)をウィキテキストファイルであるという前提で扱います。

ソースファイルのヘッダー

ほとんどのライセンスに準拠するには、各ソースファイルの先頭に次に類する記述(GPLv2 PHPアプリケーションに固有のもの)が必要です。

<?php
/**
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 * 
 * @file
 */

ライセンス

一般的にライセンスはSPDX標準に従ってフルネームまたは頭字語を照合します。Manual:$wgExtensionCredits#ライセンスも参照してください。

リリースノート

wikiユーザ及びサーバ管理者や管理者または拡張機能の作者に影響を与える可能性があるコアソフトウェアへの重要な変更はすべて (すべてのバグ修正レポートを含めて) RELEASE-NOTES-N.NNファイルに記録します。RELEASE-NOTES1.35は開発中です。過去のリリースノートはリリースごとに毎回、HISTORYファイルに移動され、リリースノートは新たに作成されます。一般にRELEASE-NOTES-N.NNは次の3つの部分から構成されています。

  • 設定変更とは対象を閲覧して「これは自分のウィキにふさわしいか?」と決定するサーバ管理者を必要とするような、許容された既定の動作への変更に加え、後方互換性のない変更またはその他を置いておく場所です。必要に応じて以前の機能を復元する方法の簡単な説明を含めるようにしてください。
  • バグ修正とは、問題のある、または望ましくないと認識される動作に対し、これらを修正する変更を書き留める場所です。これらの問題はしばしばPhabricatorで報告されますが、必ずしもそうとは限りません。
  • 新機能とは字で書いたとおり、新しく追加された機能の記録です。

追加として、特定の構成要素 (例: 操作API) や、上記のカテゴリ以外の変更を含めるセクションが存在する場合があります。

どの場合も、変更がPhabricatorに報告された1つ以上の問題に対応する場合は、エントリの先頭にタスクIDを含めます。新しいエントリはセクションの終わりに時系列順に追加します。

システムメッセージ

新しいシステムメッセージを作成するときは、ファイル名の大文字小文字表記はキャメルケースあるいはsnake_case (アンダースコア区切り) ではなく、可能な限りハイフン区切り (-) を使用してください。不適切な命名例としてsomeNewMessagesome_new_messagesome-new-messageなどがあげられます。

もし当該のメッセージを直後に半角コロン (:) を伴うラベルとして使用する場合は、コロンはハードコードしないで、それもメッセージ文内に記述します。コロンの扱いは言語に依存し (例えばフランス語ではコロンの前に半角アキが必要) 、そのため、コロンをハードコードしてしまうと地域化ができません。[[Special:MyLanguage/i18n#Symbols, colons, brackets, etc. are parts of messages|他のいくつかのタイプの約物 (interpunctuation) にも同じことが言えます]]。

メッセージキーは即席で作るのではなく、コード内で「省略せず」使います。これによりコードベースで検索するのが容易になります。たとえば下記の例ではtemplatesused-sectionの検索で省略したメッセージ・キーを使用した場合、このようなメッセージ・キーが検出されない点を示しています。

// No:
return wfMessage( 'templatesused-' . ( $section ? 'section' : 'page' ) );

// Yes:
$msgKey = $section ? 'templatesused-section' : 'templatesused-page';
return wfMessage( $msgKey );

メッセージを即席に作成しなければならないと思う場合は、コメントを付けて、付近に記述され当てはまりそうなメッセージをすべて記入しておきます。

// Messages that can be used here:
// * myextension-connection-success
// * myextension-connection-warning
// * myextension-connection-error
$text = wfMessage( 'myextension-connection-' . $status )->parse();

メッセージキーの作成、使用、文書化および保守に関する規則の詳細については地域化を参照してください。

好ましい綴り

UIに統一性をもたせるには、UIとコードベースで用語のスペルがぶれないようにすることも重要です。開発史上の経緯により、英語のメッセージやコメント、説明文書では「アメリカ英語」を優先します。

メッセージキーの短縮形

ph
プレースホルダー (placeholder: 入力欄内のテキスト)
tip
ツールチップ テキスト (tooltip text)
tog-xx
利用者の個人設定内のトグル (toggle) オプション (訳注: チェックボックス)

句点

タイトル以外のエラーメッセージは文として扱われ、句読点が必要です。

Improve the core

If you need some additional functionality from a MediaWiki core component (PHP class, JS module etc.), or you need a function that does something similar but slightly different, prefer to improve the core component. Avoid duplicating the code to an extension or elsewhere in core and modifying it there.

リファクタリング

修正を加えるたびにコードのリファクタを実行:修正のだびにコードの悪化を蓄積しないでください。

ただし、リファクタリングが大量に及ぶ場合は、コミットを分割して行います。構築ガイドArchitecture guidelines (草案) も参照してください。

HTML

MediaWiki HTTPレスポンスの出力は、2つのソースのうちの1つによって生成されます。MediaWikiのPHPコードはユーザインターフェイスの信頼できるソースであり、出力できるのは任意のHTMLです。パーサがHTMLに変換するウィキテキストでユーザが生成したものには信頼性の低いソースもあります。「Template」名前空間には、ユーザがウィキテキストを介して作成した複雑なHTMLがしばしば見られます。パーサが生成したHTMLは、出力前にサニタイズされます。

ほとんどのデータ属性は、ユーザがウィキテキストとテンプレートで使用できるようにしてあります。しかしながら以下の制限された接頭辞は、ウィキテキストでは使用できません。この方法でクライアントJavaScriptコードから、DOM要素が信頼できるソース由来かどうか判断できます。

  • data-ooui – この属性はOOUIウィジェットが生成しHTML形式で表現されます。
  • data-parsoid – Parsoidの内部使用限定で予約された属性です。
  • data-mw及びdata-mw-... – MediaWikiコア、外装 (スキン) 及び拡張機能による内部使用向けに予約済みの属性。 data-mwはParsoidでも使われます。

JavaScriptの要素を選択するとき属性のキー/値を特定すると、意図する信頼できるソース由来のDOM要素に限定して対象とするように設定できます。 サンプル: 正式な差分表示のために'wikipage.diff'フックに限定して起動します

注記

外部リンク