PHP コーディング規約
Topics
- PHP
- シングルクォートとダブルクォート
- インデント
- ブレース (波かっこ) の形式
- 「elseif」を使うこと。「else if」は使わない
- 配列の宣言
- クロージャー (無名関数)
- 複数行での関数呼び出し
- 正規表現
- 開始、終了の PHP タグ
- PHP ショートタグは禁止
- 文末の空白の除去
- スペースの使い方
- SQL 文の書式
- データベースクエリ
- 命名規則
- 1つのファイルでは、1つのオブジェクト構造 (クラス、インターフェース、トレイト) のみを宣言する
- 関数の引数には意味のあるフラグ値を使用する
- ダイナミックフック名での変数展開の利用
- 三項演算子
- ヨーダ記法
- 賢いコード
- エラー制御演算子 @
- extract() は使わない
- クレジット
WordPress の一部の PHP コードには一貫性に欠ける部分があります。WordPress ではユーザーの支援も得ながら徐々にこれらを改善し、コードをクリーンで読みやすいものにするよう努めています。
WordPress において PHP のコードを書く場合はこの規約に従ってください。これは WordPress コアのプログラミングだけではなく、プラグインやテーマの作成でも同様です。規約は多くの点で「Pear standards」に似ていますが、一部異なる部分もあります。
PHP インラインドキュメント規約も参照してください。
PHP
シングルクォートとダブルクォート
シングルクォートとダブルクォートは適切に使い分けてください。文字列で何も評価しない場合は、シングルクォートを使用してください。クォートの種類を入れ替えれば済むため、文字列の中でエスケープを使用する必要はほとんどないはずです。
echo '<a href="/static/link" title="Yeah yeah!">Link name</a>';
echo "<a href='$link' title='$linktitle'>$linkname</a>";
属性値の途中にシングルクォートやダブルクォートがあると属性値が途中で終了し、HTML は不正になり、セキュリティ問題を引き起こします。属性値は esc_attr() を通してください。詳細については「データ検証」を参照してください。
インデント
インデントは常に論理的な構造を反映してください。インデントには本物のタブを使用します。スペースは使わないでください。大部分のクライアント環境で最大の柔軟性を得られます。
例外: コードブロックの可読性のために必要であれば、スペースを使用してください。
[tab]$foo = 'somevalue';
[tab]$foo2 = 'somevalue2';
[tab]$foo34 = 'somevalue3';
[tab]$foo5 = 'somevalue4';
連想配列では複数の要素を含む場合、値は新しい行から始めてください。
$query = new WP_Query( array( 'ID' => 123 ) );
$args = array(
[tab]'post_type' => 'page',
[tab]'post_author' => 123,
[tab]'post_status' => 'publish',
);
$query = new WP_Query( $args );
注意: 配列の最後の要素に続くコンマは推奨です。配列の要素を簡単に並べ替えることができ、新しい項目が追加されても diff の結果が明確です。
$my_array = array(
[tab]'foo' => 'somevalue',
[tab]'foo2' => 'somevalue2',
[tab]'foo3' => 'somevalue3',
[tab]'foo34' => 'somevalue3',
);
switch
構造では、case
は switch
文から1タブ分インデントし、break
は case
文から1タブ分インデントしてください。
switch ( $type ) {
[tab]case 'foo':
[tab][tab]some_function();
[tab][tab]break;
[tab]case 'bar':
[tab][tab]some_function();
[tab][tab]break;
}
ルール: 行の先頭はタブでインデントし、途中を揃える場合にスペースを使用してください。
ブレース (波かっこ) の形式
すべてのブロックに対して以下の形式でブレースを使用してください。
if ( condition ) {
action1();
action2();
} elseif ( condition2 && condition3 ) {
action3();
action4();
} else {
defaultaction();
}
その上で非常に長いブロックがあれば、複数の短いブロック、関数、メソッドに分割できないかを検討してください。分割することで複雑度を解消し、テストしやすくなり、可読性を向上します。
ブレースは必ず使用してください。省略可能な場合でも使用してください。
if ( condition ) {
action0();
}
if ( condition ) {
action1();
} elseif ( condition2 ) {
action2a();
action2b();
}
foreach ( $items as $item ) {
process_item( $item );
}
注意: 「単一文のインライン制御構造」でのブレースは使用できません。「制御構造に関する別の構文」は使用しても構いません (例: 「if」と「endif」、「while」と「endwhile」)。これらは特に、テンプレート内で HTML に PHPコードを埋め込む際に使用されます。
<?php if ( have_posts() ) : ?>
<div class="hfeed">
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID() ?>" class="<?php post_class() ?>">
<!-- ... -->
</article>
<?php endwhile; ?>
</div>
<?php endif; ?>
「elseif」を使うこと。「else if」は使わない
「else if」は「if|elseif」ブロックのコロン構文と互換性がありません。条件式では「elseif」を使用してください。
配列の宣言
配列の宣言では、一般に長い配列構文 (array( 1, 2, 3 )) の方が短い配列構文 ([ 1, 2, 3 ]) よりも可読性に優れます。これは主に視覚的な面からから来ますが、加えて初心者にとっても分かりやすくなります。
配列は常に長い配列構文で宣言してください。
クロージャー (無名関数)
必要であれば、コールバックに渡す際、新規に関数を作成する代わりにクロージャーを使うことができます。例えば、
$caption = preg_replace_callback(
'/<[a-zA-Z0-9]+(?: [^<>]+>)*/',
function ( $matches ) {
return preg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
},
$caption
);
クロージャーをフィルターやアクションのコールバックとして渡すことはできません。これは remove_action()
や remove_filter()
で削除できないためです。この問題を解決する提案については #46635 を参照してください。
複数行での関数呼び出し
関数呼び出しを複数行に分割する場合、1行ずつパラメータを並べてください。インラインコメントも単体で1行にしてください。
各パラメータはそれ以上複数行に分割しないでください。複数行必要なパラメータ値は、まず変数に割り当て、次にその変数を関数呼び出しに指定してください。
$bar = array(
'use_this' => true,
'meta_key' => 'field_name',
);
$baz = sprintf(
/* translators: %s: Friend's name */
esc_html__( 'Hello, %s!', 'yourtextdomain' ),
$friend_name
);
$a = foo(
$bar,
$baz,
/* translators: %s: cat */
sprintf( __( 'The best pet is a %s.' ), 'cat' )
);
正規表現
POSIX 互換関数 ではなく、Perl 互換の正規表現 (PCRE preg_
関数) を使用してください。決して「/e
」修飾子は使わず、代わりに「preg_replace_callback
」を使用してください。
正規表現には、一重引用符で囲む文字列を使用するほうが便利です。二重引用符で囲む文字列とは異なり、一重引用符で囲む文字列には2つのメタシークエンス「\’
」と「\\
」しかないためです。
開始、終了の PHP タグ
HTML ブロック内に複数行の PHP コードを埋め込む場合、PHP 開始タグ、終了タグはそれぞれ1行を使用してください。
正しい (複数行):
function foo() {
?>
<div>
<?php
echo bar(
$baz,
$bat
);
?>
</div>
<?php
}
正しい (単一行):
<input name="<?php echo esc_attr( $name ); ?>" />
間違い:
if ( $a === $b ) { ?>
<some html>
<?php }
PHP ショートタグは禁止
重要 絶対に PHP のショートタグは使わないでください。
正しい:
<?php ... ?>
<?php echo $var; ?>
間違い:
<? ... ?>
<?= $var ?>
文末の空白の除去
コードの各行末尾のスペースは削除してください。ファイル末尾の PHP 終了タグの除去は推奨です。終了タグを使用する場合には、その後にスペースがないことを確認してください。
スペースの使い方
コンマの後ろや、論理演算子、比較演算子、文字列演算子、代入演算子の両側には、常にスペースを入れてください。
x === 23
foo && bar
! foo
array( 1, 2, 3 )
$baz . '-5'
$term .= 'X'
「if」「elseif」「foreach」「for」「switch」ブロックの開きかっこ、閉じかっこの両側にも入れてください。
foreach ( $foo as $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)
を使用してください。
foreach ( (array) $foo as $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 );
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()
」がエスケープやクォートを実行します。この結果、毎回 esc_sql() を使用する必要はありません。クエリを呼び出しさえすればエスケープは正しく処理されるため、各要素がエスケープされているかどうかを一々確認する必要もありません。
詳細については「データ検証」を参照してください。
データベースクエリ
データベースには直接触らないでください。必要なデータを取得する関数があれば、それを使用してください。クエリの代わりに関数を使用したデータベースの抽象化を利用すると、コードは前方互換性を保ち、結果がメモリー内にキャッシュされる場合は何倍も速くなります。
データベースに触る必要があると考える場合は wp-hackers メーリングリストにメッセージを投稿し、開発者と連携してください。必要な機能を備えた関数の作成が次の WordPress バージョンで検討されるかもしれません。
命名規則
変数、アクション、関数の名前にはアルファベット小文字を使います。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
このファイル命名規則は、すべての現行のクラスファイル、将来のクラスファイルに適用されます。例外は BackPress に移植されたコードを含む3つのファイル「class.wp-dependencies.php」「class.wp-scripts.php」「class.wp-styles.php」で、これらは接頭辞が class.
のように、ハイフンの代わりにドットで始まります。
wp-includes
内のテンプレートタグを含むファイルには、分かりやすさのため名前の末尾に -template
を付けてくだださい。
general-template.php
1つのファイルでは、1つのオブジェクト構造 (クラス、インターフェース、トレイト) のみを宣言する
例えば、ファイル class-example-class.php
には1つのクラスしか入れられません。
// 間違い: ファイル class-example-class.php
class Example_Class { [...] }
class Example_Class_Extended { [...] }
2つ目のクラスは、個別のファイル class-example-class-extended.php
に置きます。
// 正しい: ファイル class-example-class.php
class Example_Class { [...] }
// 正しい: ファイル class-example-class-extended.php
class Example_Class_Extended { [...] }
関数の引数には意味のあるフラグ値を使用する
関数を呼び出す場合は、単に true
や false
を使用するのではなく、文字列値を使用してください。
// 間違い
function eat( $what, $slowly = true ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', true ); // true って、どういうこと?
eat( 'dogfood', false ); // false って、どういうこと? true の反対ってこと?
PHP は名前付き引数をサポートしないためフラグの値には意味がありません。この結果、上のような例に出会うたびに関数定義を探す必要が出てきます。ブール値の代わりに説明的な文字列値を使用することで、コードは読みやすくなります。
// 正しい
function eat( $what, $speed = 'slowly' ) {
...
}
eat( 'mushrooms' );
eat( 'mushrooms', 'slowly' );
eat( 'dogfood', 'quickly' );
関数パラメータに説明を加えたければ、配列 $args
が良いパターンです。
// もっと良い
function eat( $what, $args ) {
...
}
eat ( 'noodles', array( 'speed' => 'moderate' ) );
ダイナミックフック名での変数展開の利用
ダイナミックフックの名前では読みやすさ、検索のしやすさのため、変数の連結でなく、展開を使用してください。
ダイナミックフックはタグ名に動的な値を含むフックです。例: {$new_status}_{$post->post_type} (publish_post)
フックタグで使用される変数は中括弧(「{」と「}」)で囲み、完全なタグ名全体をダブルクオートで囲んでください。こうすると PHP は、挿入された文字列内で指定された変数の型を正しくパースできます。
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );
このときタグ名内の動的な値はできるだけ簡潔で分かりやすいものにしてください。$user_id
の方がたとえば $this->id
などよりも明確です。
三項演算子
三項演算子は使用しても構いませんが、常に文が 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);
ヨーダ記法
if ( true === $the_force ) {
$victorious = you_will( $be );
}
変数を伴う論理比較を行う場合、常に変数を右側に、定数や文字列や関数呼び出しを左側に置いてください。どちらも変数でなければ、順序は重要ではありません (コンピューターサイエンスの言葉では、比較時、常に l-value を右意、r-value を左に置きます)。
上の例で1つ等号を忘れると (白状すると、熟練のコアメンバーでもやらかします)、定数 true
に代入できないためパースエラーが発生します。もし条件式が ( $the_force = true )
であれば、代入は構文として正しく 1
を返し、結果 if 文は true
と評価し、そして、しばらくバグと闘うことになるでしょう。
ヨーダ記法は最初、奇妙に見えるかもしれませんが、そのうち慣れるはずです。
なおヨーダ記法は「==
」「!=
」「===
」「!==
」で使用してください。「<」「>」「<=」「>=」では読みづらいため避けてください。
賢いコード
一般にコードの読みやすさは賢さや短さよりも重要です。
isset( $var ) || $var = some_function();
上のコードは賢いかもしれませんが、構文に慣れていなければ完全に理解するまで時間がかかります。それよりも次のように書くべきです。
if ( ! isset( $var ) ) {
$var = some_function();
}
本当に必要でない限り、緩やかな比較 (loose comparison) は、動作を誤解しやすいため、使用しないでください。
正しい:
if ( 0 === strpos( 'WordPress', 'foo' ) ) {
echo __( 'Yay WordPress!' );
}
間違い:
if ( 0 == strpos( 'WordPress', 'foo' ) ) {
echo __( 'Yay WordPress!' );
}
条件の中で代入しないでください。
正しい:
$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 7.2 では非推奨となりました。両方の関数を使わないでください。
エラー制御演算子 @
PHP ドキュメント によると
PHP はエラー制御演算子(@)をサポートしています。PHP の式の前に付けた場合、その式により生成されたエラーメッセージは無視されます。
この演算子がコア内に存在すると、適切なエラーチェックが行われずしばしば遅れて適用されます。決して使用しないでください。ちなみに PHP のドキュメントにさえ次のような箇所があります。
警告: 現在、エラー制御演算子プレフィックス”@”は、スクリプトの実行を 終了するような致命的なエラーの出力さえ抑圧します。このため、ある関数の エラー出力を抑制するために “@” を使用した場合、その関数が 利用できなかったり、ミスタイプがあった場合でも、原因を示すことなく その場所でスクリプトは終了してしまいます。
extract() は使わない
#22400: Remove all, or at least most, uses of extract() within WordPress によれば、
extract()
はデバッグしにくいし、コードも読みにくい、ひどい関数。使うのは禁止、中で使ってるのも全部削除しよう。 Joseph Scott が 何がそんなにひどいか書いてる。
クレジット
- PHP 規約: Pear standards
主な変更
- 2013/11/13: ブレースは常に使う。オプションの場合でも使う。
- 2014/6/20: 「エラー制御演算子 @」の説明を追加。エラー制御演算子 (@) の使用は禁止。参照 #wordpress-dev。
- 2014/10/20: ブレースの更新 – 「制御構造に関する別の構文」の使用の許可、というか推奨。禁じられた「単一行のインライン制御構造」。
- 2014/1/21: extract() 禁止を追加
最終更新日: