Manual:Coding conventions/PHP/ja

このページでは、の PHP で書かれたファイル内でのコーディング規約を説明します. PHP を含むすべてのプログラミング言語に適用されるも参照してください. コミットの確認に役立つ短いチェックリストが必要な場合は、 を使用してみてください.

PHP_CodeSniffer (別名 PHPCS) は、MediaWiki 用のカスタム ルールセットを使用して、ほとんどのコード スタイル規則を自動的に修正、または少なくとも検出できます. 詳細情報は を参照してください.



空白
MediaWiki は、読みやすさを最適化するために、間隔が広いスタイルを優先します.

空白ではなくタブでインデントをします. 行の長さを 120 文字までに制限します (タブ幅は4文字として数えます).

二項演算子の前後に空白を入れます. 例:

括弧内が空の場合を除いて、括弧の隣 (内側) に空白を入れます. 関数名の後に空白を入れないでください.

関数の戻り値の型ヒントでは、 の後ろに空白を入れますが、前には入れません:

配列を宣言する際は、配列が空の場合を除いて、角括弧内に空白を入れます. 配列要素にアクセスする際は、角括弧内に空白を入れないでください.

、、、、 や、 キーワードなどの制御構造の直後に、空白を入れるべきです:

型キャストの場合は、キャスト演算子の中または後に空白を使用しないでください:

コメントでは、 文字または 文字とコメントの間に1つの空白を入れるべきです.



三項演算子
は、式が非常に短く明白な場合に有効に使用できます:

ただし、三項演算子を含む複数行の式を検討している場合は、代わりに ブロックの使用を検討してください. ディスク領域は安価で、コードの可読性が最優先であり、「if」が英語で「 」はそうではないことを忘れないでください. 複数行の三項式を使用している場合、疑問符とコロンは、MediaWiki の JavaScript 規則とは対照的に、1 行目と 2 行目の末尾ではなく、2 行目と 3 行目の先頭に置く必要があります.

MediaWiki は PHP 以降を必要とするため、PHP 5.3 で導入されたエルビス演算子 (elvis operator) としても知られる shorthand 三項演算子  の使用が許容されます.

PHP 7.0 以降、null 合体演算子も利用可能であり、一部のユース ケースでは三項演算子をこれに置換できます. 例えば、 の代わりに、以下のように書けます:



文字列リテラル
一重引用符が二重引用符と同等であるすべての場合について、一重引用符の使用が推奨されます. 一重引用符を使用したコードは、誤ってエスケープ シーケンスや変数を含めることができないため、誤りが発生しにくく、レビューが容易です. 例えば、正規表現 には追加のバックスラッシュが必要であるため、 よりも少し混乱を生じて誤りが発生しやすくなります. また、米国/英国の QWERTY キーボードを使用している場合は、Shift キーを押す必要がないため、入力が簡単です.

ただし、PHP の二重引用符で囲まれた文字列補間機能を使用することを恐れないでください:

これは、連結 (ドット) 演算子を使用した同等の機能よりもわずかに優れたパフォーマンス特性を備えており、見た目もよくなっています.

ヒア ドキュメント スタイルの文字列が役立つ場合があります:

一部の作者は、終了トークンとして END を使用することを好みますが、これは PHP 関数の名前でもあります.



関数とパラメーター
膨大な数のパラメーターを関数やコンストラクターに渡さないでください:

パラメーターの順序を素早く覚えられなくなります. 必然的に、リストの最後にあるパラメーターをカスタマイズするためだけに、呼出し元のすべての既定値をハード コーディングする必要があります. このような関数をコーディングしたい場合は、代わりに名前付きパラメーターの連想配列を渡すことを検討してください.

一般に、関数では真偽値パラメーターの使用は推奨されていません. では、 の説明文書を調べないと、これらのパラメーターが何を示しているのかを理解できません. クラス定数を使用し、汎用フラグ パラメーターを作成する方が、はるかに優れています.



または、関数に名前付きパラメーターの配列を渡すには、以下のようにします:



関数の過程で変数を再利用しないように心がけ、関数に渡されるパラメーターの変更を避けてください (パラメーターが参照渡しされ、値の変更がその関数の本質である場合を除きます).



代入式
代入文を式として使用することは、読者にとって意外なことであり、誤りのように見えます. 以下のようなコードを記述しないでください:

空白は安価であり、あなたは高速タイピングできるでしょうから、代わりに以下を使用してください:

反復について、以前は 句での代入は合理的でした:

上記は新しいコードでは不要です. 代わりに以下を使用してください:



C からの拝借
PHP 言語は、大好きな C 言語の機能を PHP に持ち込みたいと考えている人々によって設計されました. しかし、PHP には C と比較していくつかの重要な違いがあります.

C では、定数はプリプロセッサー マクロとして実装され、高速です. PHP では、定数名の実行時ハッシュ テーブルの検索で実装されており、文字列リテラルを使用するよりも低速です. C で列挙型または列挙型風のマクロの集合を使用するほとんどの場所で、PHP では文字列リテラルを使用できます.

PHP には 3 つの特殊なリテラルがあり、大文字/小文字/大文字小文字の混在は PHP では重要ではありませんが (PHP 5.1.3 以降)、我々の規則では常に以下のような小文字です: 、、.

を使用し、 は使用しないでください. これらには微妙に異なる意味があります:

そして後者はパフォーマンスが劣ります.



制御構造の代替構文
PHP は、コロンや 、 、などのキーワードを使用した制御構造の代替構文を提供します:

この構文は、多くのテキスト エディターで中括弧を自動的に照合して折りたたむ機能を妨げるため、避ける必要があります. 代わりに中括弧を使用する必要があります:



括弧の配置
Manual:コーディング規約#インデントと配置を参照してください.

無名関数の場合、無名関数が 1 行で構成される場合はアロー関数を使用することを推奨します. アロー関数は通常の無名関数よりも簡潔で読みやすく、また 1 行の無名関数に起因する書式の問題をうまく回避します.



関数パラメーターでの型宣言
該当する場合は、型宣言および戻り値型宣言 (型ヒント) を使用します.

7.4 未満の PHP は、サブクラスでの型ヒントの制限/緩和を処理できないことにご注意ください.

スカラー型ヒントは、PHP 7.2 への切り替えに従い、MediaWiki 1.35 以降で使用できます. (T231710).

nullable なパラメーターには PHP 7.1 の構文を使用し、以下を選択します:

以下は使用しません:

前者は、省略可能なパラメーターとの曖昧さを回避しつつ、パラメーターの null 可能性を正確に伝えます. IDE や静的解析ツールも、それを認識し、nullable なパラメーターの後に nullable ではないパラメーターが続く場合、エラーを報告しません.

命名
関数または変数に名前を付けるときは、ローワー キャメル ケース (lowerCamelCase) を使用します. 例:

クラスに名前を付けるときはアッパー キャメル ケース (UpperCamelCase) を使用します:. グローバル定数とクラス定数には大文字とアンダースコアを使用します:,. その他の変数は小文字またはローワー キャメル ケース (lowerCamelCase) にし、変数名にアンダースコアは使用しないようにします.

さまざまな場所で使用される接頭辞もいくつかあります:

関数

 * (wiki functions: ウィキ関数) – トップ レベルの関数. 例:
 * (extension functions: 拡張機能の関数) = 拡張機能のグローバル関数. ただし、「ほとんどの場合、最新のスタイルでは、フック関数を静的メソッドとしてクラスに配置するため、そのように名前を付ける生のトップレベル関数をほとんどまたはまったく残しません. 」 (-- brion が Manual_talk:Coding_conventions で)

動詞句が推奨されます. ではなく を使用してください. テストで使用するために関数を公開する場合は、安定したインターフェイス方針に従い、これらに  をつけてください. これらを誤用したり非公式に依存したりすることは、ほとんどの内部メソッドよりも問題が深刻であり、そのため、これらがテスト環境外で実行された場合には例外をスローするようにする傾向があります.

変数

 * – グローバル変数. 例: . 新しいグローバル変数を宣言する場合は常に「」を使用してください. これにより、不足している宣言を見つけやすくなります.  拡張機能では、拡張機能の名前を名前空間の区切りとして使用する必要があります. (訳注: $wg と変数名を拡張機能名で区切る) 例えば、 ではなく  を使用します.
 * 関数内でグローバル宣言をする場合は、依存関係が関数全体を読まなくてもわかるように、関数の先頭に配置する必要があります.

クラスのインスタンスを使うことは一般的です. 私たちはこれらのために命名規則を持っており、接続されているサーバーの性質を把握するのに役立ちます. この点は、ウィキメディアや他の大規模なウィキなどのレプリケーション環境で特に重要です. 開発環境では、通常、これら 2 つのタイプの違いはありませんが、これは微妙なエラーを隠すことがあります.


 * – 書き込み用の  オブジェクト (プライマリ接続)
 * – 並列セーフではない読み取り用の  オブジェクト (これは読み取り専用レプリカであり、主要な接続よりも若干遅れているため、これを使用してデータベースに書き込みを試みたり、権限やブロック状態のような重要なクエリに「正式な」回答を得ようとしてはなりません)

古いコードに以下のようなものが見られますが、新しいコードでは推奨されていません:


 * – セッション変数. 例:
 * – Cookie 変数. 例:
 * – POST 変数 (フォームフィールドを介して送信される). 例:
 * – オブジェクト メンバー変数: . この方法は新しいコードでは推奨されていませんが、クラス内では一貫性を保つようにしてください.

関数はエラーを抑制したい場合にのみ使用するべきです. それ以外の場合は、 (ブール変換) を使用してください.

よくある使用例: 既定で に設定された省略可能な真偽値の構成キー.
 * essentially does.
 * 真偽値変換の落とし穴に注意してください.
 * 未定義のプロパティや変数に関するエラーを抑制します. 未定義かどうかをテストする場合は、 を使用してください.  「空」の値をテストする意図しかない場合 (例: 、0、 など)、  を使用してください.

をテストするために を使用しないでください. このような場合に を使用すると、変数名の綴りが誤っている場合にエラーを隠す可能性があるため、エラーが発生する可能性があります. 代わりに、 を使用してください.



真偽値の変換

 * 文字列や配列が空かどうかをテストするために  または  を使用しないでください. PHP では、 が false と見なされますが、 は MediaWiki の有効なページ名や利用者名であるためです.  代わりに   または   を使用してください.
 * 真偽値への変換の規則を学びましょう. 文字列を真偽値に変換する場合には注意してください.

その他

 * 配列の加算は、数字添字の配列のキーを再度番号付けしないため となります.  配列のキーを再度番号付けしたい場合は  を使用してください:
 * に  が設定されていることを確認してください.  これにより、ストック PHP が無視する未定義の変数やその他の微妙なトラップについて通知されます.   も参照してください.
 * PHP ファイルが純粋な場合 (例: HTML テンプレートではない場合)、末尾の タグを省略してください.  これらのタグは、末尾の空白と「ヘッダーが送信済み」というエラー メッセージの問題を引き起こすことがあります (17642 と http://news.php.net/php.general/280796 を参照).  バージョン管理では、ファイルの末尾に改行文字があることが慣例となっており (エディターによって自動的に追加される場合があります)、それがこのエラーを引き起こす原因となることがあります.
 * 5.3 で導入された 構文を使用しないでください.  機能が PHP に導入されたとしても、それを使用するべきというわけではありません.
 * 必要がある場合を除いて、配列をトラバースする際には参照渡しを使わないでください. それでも使用する場合は、その結果に注意してください. (https://web.archive.org/web/20220924191559/https://www.intracto.com/en-be/blog/php-quirks-passing-an-array-by-reference/ を参照してください)
 * PHP では、非静的メソッドの中でも静的変数を宣言できます. この機能は、いくつかのケースで変数がインスタンス間で共有されるため、微妙なバグを引き起こすことがあります.    というプロパティを使わない場合は、同様に静的変数も使用しないでください.



比較演算子
== 比較演算子を使用する際は注意が必要です. 通常、より直感的な 演算子を使用することが望ましく、 を使用する理由がない限り、 を優先すべきです.


 * は (注意!)
 * は
 * To check if two scalars that are supposed to be numeric are equal, use, e.g. is true.
 * To check if two variables are both of type 'string' and are the same sequence of characters, use, e.g. is false.

Watch out for internal functions and constructs that use weak comparisons; for instance, provide the third parameter to, and don't mix scalar types in   constructs.

Do not use Yoda conditionals.

JSON number precision
JSON uses JavaScript's type system, so all numbers are represented as 64bit IEEE floating point numbers. This means that numbers lose precision when getting bigger, to the point where some whole numbers become indistinguishable: Numbers beyond 2^52 will have a precision worse than ±0.5, so a large integer may end up changing to a different integer. To avoid this issue, represent potentially large integers as strings in JSON.

Don't use built in serialization
PHP's built in serialization mechanism (the  and   functions) should not be used for data stored (or read from) outside of the current process. Use JSON based serialization instead (however, beware the pitfalls). This is policy established by RFC T161647.

The reason is twofold: (1) data serialized with this mechanism cannot reliably be unserialized with a later version of the same class. And (2) crafted serialized data can be used to execute malicious code, posing a serious security risk.

Sometimes, your code will not control the serialization mechanism, but will be using some library or driver that uses it internally. In such cases, steps should be taken to mitigate risk. The first issue mentioned above can be mitigated by converting any data to arrays or plain anonymous objects before serialization. The second issue can perhaps be mitigated using the whitelisting feature PHP 7 introduces for unserialization.



コメントおよび説明文書
It is essential that your code be well documented so that other developers and bug fixers can easily navigate the logic of your code. New classes, methods, and member variables should include comments providing brief descriptions of their functionality (unless it is obvious), even if private. In addition, all new methods should document their parameters and return values.

We use the Doxygen documentation style (it is very similar to PHPDoc for the subset that we use) to produce auto-generated documentation from code comments (see ). Begin a block of Doxygen comments with, instead of the Qt-style formatting. Doxygen structural commands start with. (Use  rather than   as the escape character – both styles work in Doxygen, but for backwards and future compatibility MediaWiki has chosen the   style.) They organize the generated documentation (using ) and identify authors (using   tags).

They describe a function or method, the parameters it takes (using ), and what the function returns (using  ). The format for parameters is:

@param type $paramName Description of parameter

If a parameter can be of multiple types, separate them with the pipe '|' character, for example:

Continue sentences belonging to an annotation on the next line, indented with one additional space.

For every public interface (method, class, variable, whatever) you add or change, provide a  tag, so people extending the code via this interface know they are breaking compatibility with older versions of the code.

FIXME usually means something is bad or broken. TODO means that improvements are needed; it does not necessarily mean that the person adding the comment is going to do it. HACK means that a quick but inelegant, awkward or otherwise suboptimal solution to an immediate problem was made, and that eventually a more thorough rewrite of the code should be done.



ソース ファイルのヘッダー
In order to be compliant with most licenses you should have something similar to the following (specific to GPLv2 applications) at the top of every source file.



Doxygen タグ
We use the following annotations which Doxygen recognizes. Use them in this order, for consistency:

ファイルのレベル:
 * @file

Class, class member, or global member:


 * @todo
 * @var
 * @stable, @newable, @deprecated, @internal, @private
 * @see
 * @since
 * @ingroup
 * @param
 * @return
 * @throws
 * @author



テストの注釈
In tests, we use the following annotations among others. These aren't merely documentation, they mean something to PHPUnit and affect test execution.


 * @depends
 * @group
 * @covers
 * @dataProvider

統合
There are a few pieces of code in the MediaWiki codebase which are intended to be standalone and easily portable to other applications. While some of these now exist as separate libraries, others remain within the MediaWiki source tree (e.g. the files in ). Apart from these, code should be integrated into the rest of the MediaWiki environment, and should allow other areas of the codebase to integrate with it in return.

可視性
Mark code as unless there is a reason to make it more visible. Don't just make everything protected (= public to subclasses) or public.



グローバル オブジェクト
Do not access the PHP superglobals, , etc, directly; use instead; there are various functions depending on what type of value you want.You can get a  from the nearest , or if absolutely necessary. Equally, do not access directly; use  if you want to get the IP address of the current user.

<span id="Static_methods_and_properties">

static メソッドおよびプロパティ
Static methods and properties can be used in PHP, but care should be taken when inheriting to distinguish between the  and   keywords. will always refer to the class in which it was defined, whereas  will refer to the particular sub-class invoking it. See the PHP documentation on Late Static Bindings for more details.

クラス
Encapsulate your code in an object-oriented class, or add functionality to existing classes; do not add new global functions or variables. Try to be mindful of the distinction between 'backend' classes, which represent entities in the database (e.g.,  ,  , etc.), and 'frontend' classes, which represent pages or interfaces visible to the user ( ,  ,  , etc.  Even if your code is not obviously object-oriented, you can put it in a static class (e.g.   or  ).

As a holdover from PHP 4's lack of private class members and methods, older code will be marked with comments such as to indicate the intention; respect this as if it were enforced by the interpreter.

Mark new code with proper visibility modifiers, including if appropriate, but do not add visibility to existing code without first checking, testing and refactoring as required. It's generally a good idea to avoid visibility changes unless you're making changes to the function which would break old uses of it anyway.

<span id="Error_handling">

エラー処理
In general, you should not suppress PHP errors. The proper method of handling errors is to actually handle the errors.

For example, if you are thinking of using an error suppression operator to suppress an invalid array index warning, you should instead perform an check on the array index before trying to access it. When possible, always catch or naturally prevent PHP errors.

Only if there is a situation where you are expecting an unavoidable PHP warning, you may use PHP's operator. This is for cases where:


 * 1) It is impossible to anticipate the error that is about to occur; and
 * 2) You are planning on handling the error in an appropriate manner after it occurs.

We use PHPCS to warn against use of the at-operator. If you really need to use it, you'll also need to instruct PHPCS to make an exemption, like so:

An example use case is opening a file with. You can try to predict the error by calling  and , but unlike  , such file operations add significant overhead and make for unstable code. For example, the file may be deleted or changed between the check and the actual  call (see TOC/TOU).

In this case, write the code to just try the main operation you need to do. Then handle the case of the file failing to open, by using the  operator to prevent PHP from being noisy, and then check the result afterwards. For  and , that means checking for a boolean false return, and then performing a fallback, or throw an exception.

AtEase
For PHP 5 and earlier, MediaWiki developers discouraged use of the  operator due to it causing unlogged and unexplained fatal errors (r39789). Instead, we used custom and  methods from the  library. The reason is that the at-operator caused PHP to not provide error messages or stack traces upon fatal errors. While the at-operator is mainly intended for non-fatal errors (not exceptions or fatals), if a fatal were to happen it would make for a very poor developer experience.

In PHP 7, the exception handler was fixed (example) to always provide such errors, including a stack trace, regardless of error suppression. In 2020, use of AtEase started a phase out, reinstating the at-operator. (T253461)

Exception handling
Exceptions can be checked (meaning callers are expected to catch them) or unchecked (meaning callers must not catch them).

Unchecked exceptions are commonly used for programming errors, such as invalid arguments passed to a function. These exceptions should generally use (either directly or by subclassing) the SPL exception classes, and must not be documented with  annotations.

Checked exceptions, on the other hand, must always be documented with  annotations. When calling a method that can throw a checked exception, said exception must either be caught, or documented in the caller's doc comment. Checked exceptions should generally use dedicated exception classes extending. It's recommended not to use SPL exceptions as base classes for checked exceptions, so that correct usage of exception classes can be enforced with static code analyzers.

The base  class must never be thrown directly: use more specific exception classes instead. It can be used in a  clause if the intention is to catch all possible exceptions, but   is usually more correct for that purpose.

In legacy code it is relatively common to throw or subclass the  class. This class must be avoided in new code, as it does not provide any advantage, and could actually be confusing (T86704).

When creating a new exception class, consider implementing  if the exception message contains variable parts, and   if the exception message is shown to users.

<span id="See_also">