1.

PHP 基本構文ルール完全ガイド (PSR-12)

編集
この記事の要点
  • PHP コードは <?php ?> タグで囲む。短縮 <?short_open_tag 設定依存で非推奨
  • 文末はセミコロン ;。変数は必ず $ プレフィックス、関数は大文字小文字を区別しない (Case-insensitive)
  • コーディング規約は PSR-12(旧 PSR-2)。インデント 4 スペース / 行末 LF / UTF-8 (BOM なし)
  • declare(strict_types=1) でファイル単位の厳密型チェック有効化。PHP 7+
  • PHP 8 系: match 式 / Enum (8.1) / readonly (8.1) / Named Arguments

PHP タグ

PHP コードは <?php   ?> タグで囲みます。タグの外は HTML として出力されます。

<?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 推奨 -->
タグ説明推奨
<?php ... ?>標準形○ 必ず使う
<?= ... ?>echo の短縮(PHP 5.4+ で常時有効)○ Blade テンプレ等で多用
<? ... ?>short_open_tag 依存× 環境差で動かない
<script language="php">PHP 7 で廃止× 使用禁止

変数と命名

// ★ 変数は必ず $ で始める
$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) { }

Case Sensitivity (大文字小文字)

要素区別する区別しない
変数名 $foo / $Foo★ 別物-
定数 FOO / Foo★ 別物(PHP 8+)(PHP 7 まで define の第3引数で制御)
クラス名-★ 同一視(PSR で大文字小文字は厳密推奨)
関数名-★ 同一視 (strlen = StrLen)
メソッド名-★ 同一視
キーワード (if / while / class)-★ 同一視

コメント

// 単行コメント (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 { }

PSR-12 コーディング規約

PSR-12 は PHP の事実上の標準スタイルガイド。PSR-1 を継承し、PSR-2 を置き換えました。

<?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();
    }
}
規約内容
インデント4 スペース(タブ禁止)
行末LF(CRLF 禁止)、末尾改行必須
エンコーディングUTF-8 + BOM なし
行の長さソフト 80 文字、ハード 120 文字推奨
クラス / メソッドの中括弧次の行
制御構文 (if/for) の中括弧同じ行
関数引数のカンマカンマ後にスペース
名前空間 / usedeclare の後、クラスの前

declare(strict_types=1)

PHP 7+ でファイル単位の厳密型チェックを有効化。第 1 行(コメント / shebang の次)に記述。

<?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 のゆるい型変換)

PHP 8.x の新機能

match 式 (PHP 8.0+)

// 旧: 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',
};

Enum (PHP 8.1+)

// 純粋 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');    // 文字列から復元

readonly プロパティ (PHP 8.1+)

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

Named Arguments (PHP 8.0+)

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 はデフォルト

空白文字とインデント

// ✅ 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){ }          // ❌

自動整形ツール

ツール用途導入
PHP-CS-Fixer整形 + 自動修正composer require --dev friendsofphp/php-cs-fixer
PHP_CodeSniffer (phpcs)規約チェックcomposer require --dev squizlabs/php_codesniffer
PHPStan静的解析(型エラー検出)composer require --dev phpstan/phpstan
Psalm静的解析(Vimeo 製)composer require --dev vimeo/psalm
Rector自動アップグレード / リファクタcomposer require --dev rector/rector

FAQ

Q: 閉じタグ ?> を書かないのはなぜ?
A: 閉じタグの後に空白や改行があると、HTTP ヘッダ送信前に出力されて「headers already sent」エラーになります。ファイル全体が PHP なら閉じタグ省略が PSR 推奨。

Q: BOM 付き UTF-8 はなぜダメ?
A: BOM の 3 バイトが出力されてしまい、上記と同じ「headers already sent」が出ます。エディタの設定で必ず BOM なしに。

Q: declare(strict_types=1) は付けるべき?
A: 新規プロジェクトは付ける推奨。型エラーが早期に発見でき、IDE 補完も効きます。既存コードはテスト整備後に段階導入を。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本的なルール
  2. 継承

最近更新/作成されたページ