タイトル: 基本的なルール
SEOタイトル: PHP 基本構文ルール完全ガイド (PSR-12)
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>PHP コードは <code><?php ?></code> タグで囲む</strong>。短縮 <code><?</code> は <code>short_open_tag</code> 設定依存で非推奨</li><li><strong>文末はセミコロン</strong> <code>;</code>。変数は必ず <code>$</code> プレフィックス、関数は大文字小文字を区別しない (Case-insensitive)</li><li><strong>コーディング規約は PSR-12</strong>(旧 PSR-2)。インデント 4 スペース / 行末 LF / UTF-8 (BOM なし)</li><li><strong>declare(strict_types=1)</strong> でファイル単位の厳密型チェック有効化。PHP 7+</li><li>PHP 8 系: <strong>match 式</strong> / <strong>Enum (8.1)</strong> / <strong>readonly (8.1)</strong> / <strong>Named Arguments</strong></li></ul></td></tr></table>
<h2>PHP タグ</h2>
<p>PHP コードは <strong><?php ?></strong> タグで囲みます。タグの外は HTML として出力されます。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
echo "Hello, World!";
?>
<!-- HTML と混在 -->
<h1>Welcome</h1>
<p>Today is <?php echo date('Y-m-d'); ?></p>
<!-- 出力専用ショートタグ(PHP 5.4+ 標準有効) -->
<p>User: <?= htmlspecialchars($name) ?></p>
<!-- ファイル全体が PHP の場合は閉じタグ ?> を省略するのが PSR-12 推奨 --></code></pre>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>タグ</th><th>説明</th><th>推奨</th></tr></thead>
<tbody>
<tr><td><code><?php ... ?></code></td><td>標準形</td><td>○ 必ず使う</td></tr>
<tr><td><code><?= ... ?></code></td><td>echo の短縮(PHP 5.4+ で常時有効)</td><td>○ Blade テンプレ等で多用</td></tr>
<tr><td><code><? ... ?></code></td><td>short_open_tag 依存</td><td>× 環境差で動かない</td></tr>
<tr><td><code><script language="php"></code></td><td>PHP 7 で廃止</td><td>× 使用禁止</td></tr>
</tbody>
</table>
<h2>変数と命名</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ★ 変数は必ず $ で始める
$name = 'Taro';
$age = 30;
$isActive = true;
// 命名規則 (PSR-12)
$userName = 'snake_case か camelCase(プロジェクトで統一)';
$user_name = 'PSR は変数の表記法を規定しない。チーム慣習に従う';
// 定数: 大文字 + アンダースコア
define('MAX_RETRY', 5);
const PI = 3.14; // クラス外 const は PHP 5.3+
// クラス: PascalCase
class UserService { }
// メソッド: camelCase
public function getUserById($id) { }
// 関数: snake_case(標準関数に合わせる慣習)か camelCase
function fetch_user($id) { }</code></pre>
<h2>Case Sensitivity (大文字小文字)</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>要素</th><th>区別する</th><th>区別しない</th></tr></thead>
<tbody>
<tr><td>変数名 $foo / $Foo</td><td>★ 別物</td><td>-</td></tr>
<tr><td>定数 FOO / Foo</td><td>★ 別物(PHP 8+)</td><td>(PHP 7 まで define の第3引数で制御)</td></tr>
<tr><td>クラス名</td><td>-</td><td>★ 同一視(PSR で大文字小文字は厳密推奨)</td></tr>
<tr><td>関数名</td><td>-</td><td>★ 同一視 (<code>strlen</code> = <code>StrLen</code>)</td></tr>
<tr><td>メソッド名</td><td>-</td><td>★ 同一視</td></tr>
<tr><td>キーワード (if / while / class)</td><td>-</td><td>★ 同一視</td></tr>
</tbody>
</table>
<h2>コメント</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 単行コメント (C++ 形式)
# 単行コメント (シェル形式、PHP 固有)
/*
* 複数行コメント
* (PSR-12 では推奨されない、PHPDoc を使う)
*/
/**
* PHPDoc コメント(API ドキュメント生成・IDE 型推論用)
*
* @param string $name ユーザー名
* @param int $age 年齢
* @return User
* @throws InvalidArgumentException
*/
public function createUser(string $name, int $age): User { }</code></pre>
<h2>PSR-12 コーディング規約</h2>
<p><a href="https://www.php-fig.org/psr/psr-12/">PSR-12</a> は PHP の事実上の標準スタイルガイド。<strong>PSR-1 を継承</strong>し、PSR-2 を置き換えました。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
declare(strict_types=1);
namespace App\Service;
use App\Model\User;
use App\Repository\UserRepository;
class UserService
{
public function __construct(
private readonly UserRepository $repository,
private readonly LoggerInterface $logger,
) {
}
public function findActiveUsers(int $limit = 100): array
{
if ($limit <= 0) {
throw new InvalidArgumentException('limit must be positive');
}
return $this->repository
->where('active', true)
->limit($limit)
->get();
}
}</code></pre>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>規約</th><th>内容</th></tr></thead>
<tbody>
<tr><td>インデント</td><td>4 スペース(タブ禁止)</td></tr>
<tr><td>行末</td><td>LF(CRLF 禁止)、末尾改行必須</td></tr>
<tr><td>エンコーディング</td><td>UTF-8 + <strong>BOM なし</strong></td></tr>
<tr><td>行の長さ</td><td>ソフト 80 文字、ハード 120 文字推奨</td></tr>
<tr><td>クラス / メソッドの中括弧</td><td>次の行</td></tr>
<tr><td>制御構文 (if/for) の中括弧</td><td>同じ行</td></tr>
<tr><td>関数引数のカンマ</td><td>カンマ後にスペース</td></tr>
<tr><td>名前空間 / use</td><td>declare の後、クラスの前</td></tr>
</tbody>
</table>
<h2>declare(strict_types=1)</h2>
<p>PHP 7+ で<strong>ファイル単位</strong>の厳密型チェックを有効化。第 1 行(コメント / shebang の次)に記述。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php
declare(strict_types=1); // ★ ファイル先頭
function add(int $a, int $b): int {
return $a + $b;
}
add(1, 2); // OK: 3
add('1', '2'); // ★ TypeError(strict_types=1 の場合)
// strict_types=1 が無いと暗黙キャスト
// add('1', '2') → 3 が返る(PHP のゆるい型変換)</code></pre>
<h2>PHP 8.x の新機能</h2>
<h3>match 式 (PHP 8.0+)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 旧: switch (フォールスルー / 緩い比較)
switch ($status) {
case 'pending':
case 'processing':
$label = 'waiting';
break;
case 'done':
$label = 'complete';
break;
default:
$label = 'unknown';
}
// 新: match (式 / 厳密比較 / 値を返す)
$label = match ($status) {
'pending', 'processing' => 'waiting',
'done' => 'complete',
default => 'unknown',
};</code></pre>
<h3>Enum (PHP 8.1+)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 純粋 Enum
enum Status {
case Active;
case Inactive;
case Suspended;
}
// Backed Enum (値付き)
enum Status: string {
case Active = 'active';
case Inactive = 'inactive';
case Suspended = 'suspended';
public function label(): string {
return match($this) {
self::Active => '有効',
self::Inactive => '無効',
self::Suspended => '停止中',
};
}
}
$s = Status::Active;
echo $s->value; // active
echo $s->label(); // 有効
$s2 = Status::from('inactive'); // 文字列から復元</code></pre>
<h3>readonly プロパティ (PHP 8.1+)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">class Money {
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {}
}
$m = new Money(1000, 'JPY');
echo $m->amount; // 1000
// $m->amount = 2000; // ★ Error: Cannot modify readonly property</code></pre>
<h3>Named Arguments (PHP 8.0+)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">function createUser(string $name, int $age = 0, bool $active = true, string $role = 'user') { ... }
// 位置引数(従来)
createUser('Taro', 30, true, 'admin');
// 名前付き引数(読みやすい、デフォルト値スキップ可能)
createUser(
name: 'Taro',
role: 'admin',
); // age と active はデフォルト</code></pre>
<h2>空白文字とインデント</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// ✅ PSR-12 準拠
if ($a === 1 && $b === 2) {
foreach ($items as $key => $value) {
echo $value;
}
}
// ❌ 規約違反
if($a===1&&$b===2){
foreach($items as $key=>$value)
{
echo $value;
}
}
// 演算子周りはスペース必須
$x = $a + $b; // ✅
$x=$a+$b; // ❌
// 制御構文と括弧の間にスペース
if (cond) { } // ✅
if(cond){ } // ❌</code></pre>
<h2>自動整形ツール</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>ツール</th><th>用途</th><th>導入</th></tr></thead>
<tbody>
<tr><td><strong>PHP-CS-Fixer</strong></td><td>整形 + 自動修正</td><td><code>composer require --dev friendsofphp/php-cs-fixer</code></td></tr>
<tr><td><strong>PHP_CodeSniffer (phpcs)</strong></td><td>規約チェック</td><td><code>composer require --dev squizlabs/php_codesniffer</code></td></tr>
<tr><td><strong>PHPStan</strong></td><td>静的解析(型エラー検出)</td><td><code>composer require --dev phpstan/phpstan</code></td></tr>
<tr><td><strong>Psalm</strong></td><td>静的解析(Vimeo 製)</td><td><code>composer require --dev vimeo/psalm</code></td></tr>
<tr><td><strong>Rector</strong></td><td>自動アップグレード / リファクタ</td><td><code>composer require --dev rector/rector</code></td></tr>
</tbody>
</table>
<h2>FAQ</h2>
<p><strong>Q: 閉じタグ <code>?></code> を書かないのはなぜ?</strong><br />
A: 閉じタグの後に空白や改行があると、HTTP ヘッダ送信前に出力されて「headers already sent」エラーになります。ファイル全体が PHP なら閉じタグ省略が PSR 推奨。</p>
<p><strong>Q: BOM 付き UTF-8 はなぜダメ?</strong><br />
A: BOM の 3 バイトが出力されてしまい、上記と同じ「headers already sent」が出ます。エディタの設定で必ず BOM なしに。</p>
<p><strong>Q: <code>declare(strict_types=1)</code> は付けるべき?</strong><br />
A: 新規プロジェクトは付ける推奨。型エラーが早期に発見でき、IDE 補完も効きます。既存コードはテスト整備後に段階導入を。</p>