PHP コーディング規約
Topics
PHP 標準コーディング規約は、WordPress コミュニティ全体を対象としています。WordPress コアでは必須、テーマやプラグインでも同様に使用を推奨します。
テーマやプラグインは別のコーディングスタイルを選択できますが、この コーディング標準 は、単にコーディングスタイルに関するものではなく、WordPress エコシステムの相互運用性、翻訳性、セキュリティに関する確立したベストプラクティスを包含するものであり、別のコーディングスタイルを使用する場合でも、このベストプラクティスに関して WordPress コーディング標準を遵守することを推奨します。
すべてのコードは、(まだ) この規約に完全に準拠していませんが、新しくコミットされたコードや更新されたコードは、コーディング規約に完全に準拠する必要があります。
また、PHP インラインドキュメント規約も参照してください。
この規約への準拠を自動的にチェックしたい場合は、公式の WordPress Coding Standardsツールを使用してください。PHP_CodeSniffer を使用して実行されます。
全般
開始、終了の PHP タグ
HTML ブロック内に複数行の PHP コードを埋め込む場合、PHP 開始タグ、終了タグはそれぞれ1行を使用してください。
正しい (複数行):
function foo() {
?>
<div>
<?phpechoesc_html(
bar(
$baz,
$bat
)
);
?>
</div>
<?php
}
正しい (単一行):
<input name="<?php echo esc_attr( $name ); ?>" />
間違い:
if ( $a === $b ) { ?>
<some html>
<?php }
PHP ショートタグは禁止
重要 絶対に PHP のショートタグは使わないでください。常に完全な PHP タグを使用してください。
正しい:
<?php ... ?><?phpechoesc_html( $var ); ?>
間違い:
<? ... ?><?=esc_html( $var ) ?>
シングルクォートとダブルクォート
シングルクォートとダブルクォートは適切に使い分けてください。文字列の中で何も評価しない場合は、シングルクォートを使用してください。クォートの種類を入れ替えれば済むため、文字列の中でエスケープを使用する必要はほとんどないはずです。
echo'<a href="/static/link" class="button button-primary">Link name</a>';
echo"<a href='{$escaped_link}'>text with a ' single quote</a>";
HTML や XML の属性に入るテキストはエスケープしてください。シングルクォートまたはダブルクォートが閉じていない属性値は、HTML として無効で、セキュリティ問題を引き起こす可能性があります。詳細については、プラグインハンドブックの Data Validation を参照してください。
命名
命名規則
変数、アクション、関数の名前にはアルファベット小文字を使います。camelCase
は使いません。単語はアンダースコアで区切ります。不必要に変数名を省略しないでください。コードは明確に、理解可能なものにしてください。
function some_name( $some_variable ) { [...] }
クラス名は大文字で始まる単語をアンダースコアで区切ります。省略語はすべて大文字にします。
class Walker_Category extends Walker { [...] }
class WP_HTTP { [...] }
定数はすべて大文字で、アンダースコアで区切ります。
define( 'DOING_AJAX', true );
ファイル名はアルファベットの小文字を使用して、内容を説明する名前にしてください。単語はハイフンで区切ります。
my-plugin-name.php
クラスファイルの名前はクラス名を基にして、前に「class-」を付け、クラス名内部のアンダースコアはハイフンで置き換えます。 たとえば「WP_Error」の場合
class-wp-error.php
このファイル命名規則は、すべての現行のクラスファイル、将来のクラスファイルに適用されます。例外は 3つの古いファイル「class.wp-dependencies.php」「class.wp-scripts.php」「class.wp-styles.php」で、これらは接頭辞が class.
のように、ハイフンの代わりにドットで始まります。
wp-includes
内のテンプレートタグを含むファイルには、分かりやすさのため名前の末尾に -template
を付けてくだださい。
general-template.php
ダイナミックフック名での変数展開の利用
ダイナミックフックの名前では読みやすさ、検索のしやすさのため、変数の連結でなく、展開を使用してください。
ダイナミックフックはタグ名に動的な値を含むフックです。例: {$new_status}_{$post->post_type}
(publish_post)
フックタグで使用される変数は中括弧(「{」と「}」)で囲み、完全なタグ名全体をダブルクオートで囲んでください。こうすると PHP は、挿入された文字列内で指定された変数の型を正しくパースできます。
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
このときタグ名内の動的な値はできるだけ簡潔で分かりやすいものにしてください。$user_id
の方がたとえば $this->id
などよりも明確です。
スペース
スペースの使い方
コンマの後ろや、論理演算子、比較演算子、文字列演算子、代入演算子の両側には、常にスペースを入れてください。
SOME_CONST === 23;
foo() && bar();
! $foo;
array( 1, 2, 3 );
$baz . '-5';
$term .= 'X';
制御構造ブロックの開きかっこ、閉じかっこの両側にも入れてください。
foreach ( $fooas$bar ) { ...
関数を定義する場合は、次の形式に従ってください。
function my_function( $param1 = 'foo', $param2 = 'bar' ) { ...
function my_other_function() { ...
関数を呼び出す場合
my_function( $param1, func_param( $param2 ) );
my_other_function();
論理比較の場合
if ( ! $foo ) { ...
型のキャスト は小文字です。常に短い形式を使用してください。(integer)
でなく (int)
、(boolean)
でなく (bool)
。float については (float)
を使用してください。(real)
は使いません。PHP 7.4 で 非推奨、PHP 8 で削除されています。
foreach ( (array) $fooas$bar ) { ...
$foo = (bool) $bar;
配列要素を参照する場合には、添字が変数の場合のみ前後にスペースを入れてください。
$x = $foo['bar']; // 正しい$x = $foo[ 'bar' ]; // 間違い$x = $foo[0]; // 正しい$x = $foo[ 0 ]; // 間違い$x = $foo[ $bar ]; // 正しい$x = $foo[$bar]; // 間違い
switch
ブロックでは、case
の条件とコロンの間にスペースを置かないでください。
switch ( $foo ) {
case'bar': // 正しいcase'ba' : // 間違い
}
同様に、戻りの型の宣言のコロンの前にスペースを置かないでください。
function sum( $a, $b ): float {
return$a + $b;
}
特に指定のない限り、括弧はそれぞれの内側にスペースを置いてください。
if ( $foo && ( $bar || $baz ) ) { ...
my_function( ( $x - 1 ) * 5, $y );
インデント
インデントは常に論理的な構造を反映してください。インデントには本物のタブを使用します。スペースは使わないでください。大部分のクライアント環境で最大の柔軟性を得られます。
例外: コードブロックの可読性のために必要であれば、スペースを使用してください。
[tab]$foo = 'somevalue';
[tab]$foo2 = 'somevalue2';
[tab]$foo34 = 'somevalue3';
[tab]$foo5 = 'somevalue4';
連想配列で複数の要素を含む場合、_各項目_を、新しい行で始めてください。
$query = newWP_Query( array( 'ID' => 123 ) );
$args = array(
[tab]'post_type' => 'page',
[tab]'post_author' => 123,
[tab]'post_status' => 'publish',
);
$query = newWP_Query( $args );
注意: 配列の最後の要素に続くコンマは推奨です。配列の要素を簡単に並べ替えることができ、新しい項目が追加されても diff の結果が明確です。
$my_array = array(
[tab]'foo' => 'somevalue',
[tab]'foo2' => 'somevalue2',
[tab]'foo3' => 'somevalue3',
[tab]'foo34' => 'somevalue3',
);
switch
制御構造では、case
文は switch
文から1タブ分インデントし、case
の内容は case
の条件文から1タブ分インデントしてください。
switch ( $type ) {
[tab]case'foo':
[tab][tab]some_function();
[tab][tab]break;
[tab]case'bar':
[tab][tab]some_function();
[tab][tab]break;
}
ルール: 行の先頭はタブでインデントし、途中を揃える場合にスペースを使用してください。
文末の空白の除去
各行末尾のスペースは削除してください。ファイル末尾の PHP 終了タグの除去は推奨です。終了タグを使用する場合には、その後にスペースがないことを確認してください。
フォーマット
ブレース (波かっこ、中括弧) の形式
すべてのブロックに対して以下の形式でブレースを使用してください。
if ( condition ) {
action1();
action2();
} elseif ( condition2 && condition3 ) {
action3();
action4();
} else {
defaultaction();
}
その上で非常に長いブロックがあれば、複数の短いブロック、関数、メソッドに分割できないかを検討してください。分割することで複雑度を解消し、テストしやすくなり、可読性を向上します。
ブレースは必ず使用してください。省略可能な場合でも使用してください。
if ( condition ) {
action0();
}
if ( condition ) {
action1();
} elseif ( condition2 ) {
action2a();
action2b();
}
foreach ( $itemsas$item ) {
process_item( $item );
}
注意: ブレースの使用を義務付けるということは、「単一文のインライン制御構造」の禁止を意味します。「制御構造に関する別の構文」は使用しても構いません (例: 「if」と「endif」、「while」と「endwhile」)。これらは例えば、テンプレート内で HTML に PHPコードを埋め込む際に使用されます。
<?phpif ( have_posts() ) : ?>
<div class="hfeed">
<?php while ( have_posts() ) : the_post(); ?>
<article id="<?php echo esc_attr( 'post-' . get_the_ID() ); ?>" class="<?php echo esc_attr( get_post_class() ); ?>">
<!-- ... -->
</article>
<?php endwhile; ?>
</div>
<?php endif; ?>
配列の宣言
配列の宣言では、一般に長い配列構文 (array( 1, 2, 3 )) の方が短い配列構文 ([ 1, 2, 3 ]) よりも可読性に優れます。これは主に視覚的な面からから来ますが、加えて初心者にとっても分かりやすくなります。
配列は常に長い配列構文で宣言してください。
複数行での関数呼び出し
関数呼び出しを複数行に分割する場合、1行ずつパラメータを並べてください。インラインコメントも単体で1行にしてください。
各パラメータはそれ以上複数行に分割しないでください。複数行必要なパラメータ値は、まず変数に割り当て、次にその変数を関数呼び出しに指定してください。
$bar = array(
'use_this' => true,
'meta_key' => 'field_name',
);
$baz = sprintf(
/* translators: %s: Friend's name */__( 'Hello, %s!', 'yourtextdomain' ),
$friend_name
);
$a = foo(
$bar,
$baz,
/* translators: %s: cat */sprintf( __( 'The best pet is a %s.' ), 'cat' )
);
文、名前空間、インポート文の宣言
名前空間の宣言
名前空間の名前は、先頭が大文字の単語と、アンダースコアの区切りから構成してください。
名前空間の宣言は、宣言の前に正確に1行の空白行を入れ、宣言の後に少なくとも1行の空白行を入れてください。
namespacePrefix\Admin\Domain_URL\Sub_Domain\Event; // 正しい
名前空間の宣言は1ファイルにつき1つだけとし、ファイルの先頭に記述してください。中括弧を使用した名前空間宣言は使用できません。明示的なグローバル名前空間宣言 (名前のない名前空間宣言) も使用できません。
// 間違い: 中括弧構文を使用した名前空間宣言
namespace Foo {
// コード
}
// 間違い: グローバル名前空間での名前空間宣言
namespace {
// コード
}
WordPress コアへの名前空間の導入時期は、現在、未定です。
プラグインやテーマでの名前空間の使用を強く推奨します。他のプラグインやテーマ、WordPress コアとの名前の衝突を防ぐために、できるだけ多くのコードに接頭辞を付けてください。
ただし、競合を防ぐために、十分な長さのユニークな名前空間接頭辞を使用してください。一般には、Vendor\Project_Name
のような、会社名とプロジェクト名の組み合わせの名前空間接頭辞を使用すると良いでしょう。
警告: 名前空間接頭辞 wp
と WordPress
は WordPress 用に予約されています。
名前空間は、変数、
define()
で宣言された定数、WordPress で使用されるフック名などの非 PHP ネイティブな構成要素には影響しません。 これらには、従来どおり個別に接頭辞をつける必要があります。
オブジェクト指向プログラミング
ファイルごとに、1つのオブジェクト構造 (クラス、インターフェース、トレイト)
例えば、ファイル class-example-class.php
には1つのクラスしか入れられません。
// 間違い: ファイル class-example-class.phpclass Example_Class { [...] }
class Example_Class_Extended { [...] }
2つ目のクラスは、個別のファイル class-example-class-extended.php
に置きます。
// 正しい: ファイル class-example-class.phpclass Example_Class { [...] }
// 正しい: ファイル class-example-class-extended.phpclass Example_Class_Extended { [...] }
制御構造
「elseif」を使う。「else if」は使わない
「else if」は「if|elseif」ブロックのコロン構文と互換性がありません。条件式では「elseif」を使用してください。
ヨーダ記法
if ( true === $the_force ) {
$victorious = you_will( $be );
}
変数を伴う論理比較を行う場合、常に変数を右側に、定数や文字列や関数呼び出しを左側に置いてください。どちらも変数でなければ、順序は重要ではありません (コンピューターサイエンスの言葉では、比較時、常に l-value を右意、r-value を左に置きます)。
上の例で1つ等号を忘れると (白状すると、熟練のコアメンバーでもやらかします)、パースエラーが発生します。定数 true
に代入できないためです。もし条件式が ( $the_force = true )
であれば、代入は構文として正しく 1
を返し、結果 if 文は true
と評価し、そして、しばらくバグと闘うことになるでしょう。
ヨーダ記法は最初、奇妙に見えるかもしれませんが、そのうち慣れるはずです。
なおヨーダ記法は「==
」「!=
」「===
」「!==
」で使用してください。「<」「>」「<=」「>=」では読みづらいため避けてください。
演算子
三項演算子
三項演算子は使用しても構いませんが、常に文が true かどうかをテストしてください。false のテストは混ぜないでください、混乱するだけです。ただし「! empty()」の場合は例外です。この場合は false のテストのほうが直感的でしょう。
短い形式の三項演算子は使用しないでください。
例:
// (if statement is true) ? (do this) : (else, do this);$musictype = ( 'jazz' === $music ) ? 'cool' : 'blah';
// (if field is not empty ) ? (do this) : (else, do this);
エラー制御演算子 @
PHP ドキュメント にあるように、
PHP はエラー制御演算子(@)をサポートしています。PHP の式の前に付けた場合、その式で起こる可能性のある診断エラーは抑制されます。
この演算子がコア内に存在すると、適切なエラーチェックが行われずしばしば遅れて適用されます。決して使用しないでください。ちなみに PHP のドキュメントにさえ次のような箇所があります。
PHP 8.0.0 より前のバージョンでは、 スクリプトの実行を停止させるような致命的な場合であっても @ 演算子でエラーメッセージを抑止することが可能でした。 たとえば、存在しなかったり、ミスタイプされていたり、 利用できない関数コールの前に @ 演算子を付けると、 原因を示すことなく、その場所でスクリプトは終了してしまっていました。
データベース
データベースクエリ
データベースには直接触らないでください。必要なデータを取得する関数があれば、それを使用してください。クエリの代わりに関数を使用したデータベースの抽象化を利用すると、コードは前方互換性を保ち、結果がメモリー内にキャッシュされる場合は何倍も速くなります。
データベースに触る必要があると考える場合は、Trac チケットの作成を検討してください。そこで、WordPress の将来のバージョンに、希望する機能を持つ新しい関数を追加する可能性について議論できます。
SQL 文の書式
SQL 文が非常に複雑な場合は、複数行に分割し、インデントしても構いません。大部分の SQL 文は1行の場合と同様に動作するはずです。文の SQL の部分は「UPDATE
」や「WHERE
」のように常に大文字にしてください。
データベースを更新する関数は、渡されたパラメータが SQL 用にエスケープされていないと仮定して処理してください。エスケープはできるだけクエリの直前に、可能であれば「$wpdb->prepare()
」を使用して実行してください。
「$wpdb->prepare()
」は SQL クエリのエスケープ、クォート、整数へのキ ャストを処理するメソッドです。sprintf()
書式のサブセットを使用します。 例:
$var = "dangerous'"; // 生データ。エスケープしてもしなくても良い$id = some_foo_number(); // integer を期待するデータ。ただし確証はない$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_title = %s WHERE ID = %d", $var, $id ) );
%s
は文字列のプレースホルダーとして、%d
は整数のプレースホルダーとして使用されます。注意: これらに「クォート」はありません。 「$wpdb->prepare()
」がエスケープやクォートを実行します。この方法の良い点は、クエリーが発生するとすぐに起きるため、エスケープの有無が一目でわかる点です。
詳細については、Plugin Handbook の「Data Validation」を参照してください。
推奨
関数の引数には意味のあるフラグ値を使用する
関数を呼び出す場合は、単に true
や false
を使用するのではなく、文字列値を使用してください。
// 間違いfunction eat( $what, $slowly = true ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', true ); // true って、どういうこと?eat( 'dogfood', false ); // false って、どういうこと? true の反対ってこと?
PHP は 8.0 以降で名前付き引数をサポートします。しかし、WordPress は現在まだ古いバージョンの PHP をサポートしているため、まだ名前付き引数をを使用できません。 名前付き引数がない場合、フラグの値には意味がありません。この結果、上のような例に出会うたびに関数定義を探す必要が出てきます。ブール値の代わりに説明的な文字列値を使用することで、コードは読みやすくなります。
// 正しいfunction eat( $what, $speed = 'slowly' ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', 'slowly' );
eat( 'dogfood', 'quickly' );
関数パラメータに説明を加えたければ、配列 $args
が良いパターンです。
function eat( $what, $args ) {
...
}
eat ( 'noodles', array( 'speed' => 'moderate' ) );
このパターンを使用する際には注意が必要です。使用前に入力を検証しなければ、警告「Undefined array index (未定義の配列インデックス)」になる場合があります。このパターンは、意味のある場合のみ使用してください (たとえば、複数の引数を指定する場合など)。
賢いコード
一般にコードの読みやすさは賢さや短さよりも重要です。
isset( $var ) || $var = some_function();
上のコードは賢いかもしれませんが、構文に慣れていなければ完全に理解するまで時間がかかります。それよりも次のように書くべきです。
if ( ! isset( $var ) ) {
$var = some_function();
}
本当に必要でない限り、緩やかな比較 (loose comparison) は、動作を誤解しやすいため、使用しないでください。
正しい:
if ( 0 === strpos( $text, 'WordPress' ) ) {
echoesc_html__( 'Yay WordPress!', 'textdomain' );
}
間違い:
if ( 0 == strpos( 'WordPress', 'foo' ) ) {
echoesc_html__( 'Yay WordPress!', 'textdomain' );
}
条件の中で代入しないでください。
正しい:
$data = $wpdb->get_var( '...' );
if ( $data ) {
// Use $data.
}
間違い:
if ( $data = $wpdb->get_var( '...' ) ) {
// Use $data.
}
switch
文では、共通コードに落ちる複数の空白 case があっても構いません。しかし、case にコードがあって次のコードに落ちる場合にはその旨をコメントを記述してください。
switch ( $foo ) {
case'bar': // 正しい。空白の case はコメントなしで次に落ちて良い。case'baz':
echo$foo; // 間違い。コードを含む case は break または returnで終えるか、コメントを含む必要がある。case'cat':
echo'mouse';
break; // 正しい。break のある case にコメントは不要。case'dog':
echo'horse';
// no break // 正しい。次に落ちる旨を明確に記述したコメントがある。case'fish':
echo'bird';
break;
}
goto
文は決して使わないでください。
eval()
言語構造は 非常に危険 で、安全性を保つことが不可能です。また create_function()
関数は内部的に eval()
を実行し、PHP 8.0 では両方とも削除されました。両方の関数を使わないでください。
クロージャー (無名関数)
必要であれば、コールバックに渡す際、新規に関数を作成する代わりにクロージャーを使うことができます。例えば、
$caption = preg_replace_callback(
'/<[a-zA-Z0-9]+(?: [^<>]+>)*/',
function ( $matches ) {
returnpreg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
},
$caption
);
クロージャーをフィルターやアクションのコールバックとして渡さないでください。remove_action()
/ remove_filter()
による削除は、現時点では、複雑です (この問題を解決する提案については #46635 を参照してください)。
正規表現
POSIX 互換関数 ではなく、Perl 互換の正規表現 (PCRE preg_
関数) を使用してください。決して「/e
」修飾子は使わず、代わりに「preg_replace_callback
」を使用してください。
正規表現には、一重引用符で囲む文字列を使用するほうが便利です。二重引用符で囲む文字列とは異なり、一重引用符で囲む文字列には、エスケープが必要なものは、2つのメタシークエンス「\’
」と「\\
」しかないためです。
extract() は使わない
#22400: Remove all, or at least most, uses of extract() within WordPress によれば、
extract()
はひどい関数。コードはデバッグしにくいし、読みにいし。使うのは禁止して、中で使ってるのも全部削除しよう。
Joseph Scott が 何がそんなにひどいのかを書いています。
最終更新日: