Manual:Coding conventions/PHP/ja

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

不適切な空白スタイルのコードを開発者が修正するのを支援するために、構文をレビューして適切な場所に空白を追加する stylize と呼ばれるツールが存在します. このツールは Web インターフェイスでも利用できます. Git にコミットされたファイルに対してこれを実行することをお勧めします.

PHP_CodeSniffer 向けの規則も利用できます. 詳細情報は を参照してください. git リポジトリ  には、MediaWiki コードの PHP_CodeSniffer 設定が含まれています.

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

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

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

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

Put a space after the  in the function return type hint, but not before:

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

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

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

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

不適切な空白スタイルのコードを開発者が修正するのを支援するために、stylize と呼ばれるツールが存在し、PHP の規則によって空白が自動的に追加されます. このツールは Web インターフェイスで利用できます.

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

ただし、三項演算子を含む複数行の式を検討している場合は、代わりに ブロックの使用を検討してください. ディスク領域は安価で、コードの可読性が最優先であり、「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:コーディング規約#インデントと配置を参照してください.

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

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

Scalar typehints are allowed as of MediaWiki 1.35, following the switch to PHP 7.2 (T231710).

Use PHP 7.1 syntax for nullable parameters: choose

instead of

The former conveys precisely the nullability of a parameter, without risking any ambiguity with optional parameters. IDEs and static analysis tools will also recognize it as such, and will not complain if a non-nullable parameter follows a nullable one.

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

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

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

関数

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

動詞句が推奨されます. ではなく を使用してください.

変数

 * – グローバル変数. 例: . Always use this for new globals, so that it's easy to spot missing "" declarations. In extensions, the extension name should be used as a namespace delimiter. For example,, not.
 * Global declarations should be at the beginning of a function so dependencies can be determined without having to read the whole function.

It is common to work with an instance of the  class; we have a naming convention for these which helps keep track of the nature of the server to which we are connected. This is of particular importance in replicated environments, such as Wikimedia and other large wikis; in development environments, there is usually no difference between the two types, which can conceal subtle errors.


 * – a  object for writing (a primary connection)
 * – a  object for non-concurrency-sensitive reading (this may be a read-only replica, slightly behind primary state, so don't ever try to write to the database with it, or get an "authoritative" answer to important queries like permissions and block status)

The following may be seen in old code but are discouraged in new code:


 * – Session variables, e.g.
 * – Cookie variables, e.g.
 * – Post variables (submitted via form fields), e.g.
 * – object member variables: . This is discouraged in new code, but try to stay consistent within a class.

The function should only be used when you want to suppress errors. Otherwise just use  (boolean conversion).

Common use case: Optional boolean configuration keys that default to false. If only intending to test for undefined, use. If only intending to test for "empty" values (e.g. false, zero, empty array, etc.), use.
 * essentially does.
 * Beware of boolean conversion pitfalls.
 * It suppresses errors about undefined properties and variables.

Do not use to test for. Using in this situation could introduce errors by hiding misspelled variable names. Instead, use.

真偽値の変換
Use  or   instead.
 * Do not use  or  to test if a string or array is empty, because PHP considers  to be falsy – but  is a valid title and valid user name in MediaWiki.
 * Study the rules for conversion to boolean. Be careful when converting strings to boolean.

その他
If you want keys to be renumbered, use : This will notify you of undefined variables and other subtle gotchas that stock PHP will ignore. も参照してください. PHP may have introduced the feature, but that does not mean we should use it.
 * Array plus does not renumber the keys of numerically-indexed arrays, so.
 * Make sure you have set to.
 * When working in a pure PHP file (e.g. not an HTML template), omit any trailing  tags. These tags often cause issues with trailing white-space and "headers already sent" error messages (cf. 17642 and http://news.php.net/php.general/280796). It is conventional in version control for files to have a new line at end-of-file (which editors may add automatically), which would then trigger this error.
 * Do not use the syntax introduced in 5.3.
 * Do not pass by reference when traversing an array unless you have to. Even then, be aware of the consequences. (See https://www.intracto.com/en-be/blog/php-quirks-passing-an-array-by-reference/)
 * PHP lets you declare static variables even within a non-static method of a class. This has led to subtle bugs in some cases, as the variables are shared between instances. Where you would not use a  property, do not use a static variable either.

Equality operators
Be careful with double-equals comparison operators. Triple-equals is generally more intuitive and should be preferred unless you have a reason to use double-equals.


 * is true (!)
 * is true (!)
 * is false
 * 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 Manual:mwdocgen.php). 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
 * @ingroup
 * @author

Class, class member, or global member:


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

テストの注釈
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.

可視性
Make methods public/protected/private (think what makes sense). Don't just make everything 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.

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.

エラー処理
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.

Exceptions that indicate programming errors should be one of the exceptions that ship with PHP or a more specific subclass, while exceptions that indicate errors that are relevant to the end user should be an ErrorPageError or one of its subclasses.

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)