| この記事の要点 |
|
関数内の static 変数
function counter(): int
{
static $n = 0; // 初期化は最初の 1 回だけ
$n++;
return $n;
}
echo counter(); // 1
echo counter(); // 2
echo counter(); // 3
function normal(): int
{
$n = 0; // 毎回 0 に戻る
$n++;
return $n;
}
echo normal(); // 1
echo normal(); // 1
static を付けた変数は関数を抜けても値を保持します。ただしスコープはその関数の中だけで、外からは触れません。
// 重い処理の結果を覚えておく(メモ化)
function config(): array
{
static $cache = null;
if ($cache === null) {
$cache = require __DIR__ . '/config.php'; // 初回だけ読み込む
}
return $cache;
}
// 初期化に書けるのは定数式だけ
function bad()
{
static $t = time(); // Fatal error: Constant expression contains invalid operations
}
初期値に関数呼び出しは書けません。実行時に決まる値は null で初期化して、中で入れるのが定石です。
クラスの static プロパティ
class Counter
{
public static int $total = 0; // クラスに 1 つだけ
public int $count = 0; // インスタンスごと
public function __construct()
{
self::$total++; // static は self:: で
$this->count++; // インスタンスは $this-> で
}
}
$a = new Counter();
$b = new Counter();
echo Counter::$total; // 2 共有されている
echo $a->count; // 1 個別
echo $b->count; // 1
// インスタンス経由でも読めるが混乱のもと
echo $a::$total; // 2
// echo $a->total; // Warning: Undefined property($this-> では読めない)
| 宣言 | アクセス | 実体の数 | |
|---|---|---|---|
| インスタンスプロパティ | public int $count; | $this->count | インスタンスごと |
| static プロパティ | public static int $total; | self::$total / Counter::$total | クラスに 1 つ |
| クラス定数 | public const MAX = 10; | self::MAX | クラスに 1 つ(変更不可) |
値が変わらないなら static ではなく const を使ってください。誰かに書き換えられる心配がなくなります。
self:: と static:: の違い(遅延静的束縛)
class Base
{
public static string $name = 'Base';
public static function selfName(): string { return self::$name; }
public static function staticName(): string { return static::$name; }
}
class Child extends Base
{
public static string $name = 'Child'; // 再宣言して上書き
}
echo Child::selfName(); // Base ← self は「書かれたクラス」に固定
echo Child::staticName(); // Child ← static は「呼ばれたクラス」を見る
static:: の解決を遅延静的束縛(Late Static Binding)といいます。継承して差し替えられる前提のコードでは static::、絶対に変えたくないものは self:: を使います。
再宣言しないと親と共有される
class A { public static int $n = 0; }
class B extends A {} // 再宣言していない
B::$n = 5;
echo A::$n; // 5 ← 同じ実体を共有している
class C extends A { public static int $n = 0; } // 再宣言した
C::$n = 9;
echo A::$n; // 5 影響しない
「子クラスごとにカウンタを持たせたつもりが全部同じ値になる」のはこれが原因です。子クラスで別々に持ちたいなら、子クラス側で再宣言する必要があります。
使ってよい場面・避けるべき場面
| 用途 | 判断 |
|---|---|
| 1 リクエスト内のキャッシュ(設定・接続の使い回し) | 妥当 |
| 生成数のカウント・ID の採番 | 妥当 |
| 定数的な値の保持 | const にする |
| アプリの状態を持ち回る | 避ける。どこから変わるか追えなくなる |
| ログインユーザーなどリクエスト固有の情報 | 避ける。常駐環境では他の利用者に漏れる |
リクエストをまたいで残らない
class Visit { public static int $count = 0; }
Visit::$count++;
echo Visit::$count; // 何回アクセスしても 1
PHP はリクエストごとにプロセスの状態を捨てます。訪問回数のように残したい値は、セッション・データベース・ファイル・Redis などに保存してください。
逆に、Swoole や RoadRunner のようにプロセスを常駐させる構成では static の値が次のリクエストに残ります。利用者ごとの情報を static に入れていると、別の利用者に見えてしまいます。
テストのしづらさ
class Registry { public static array $items = []; }
// テスト A で追加した値が、テスト B にも残る
public function testA(): void { Registry::$items[] = 'x'; }
public function testB(): void { $this->assertSame([], Registry::$items); } // 失敗する
// 対処: 毎テストで戻す
protected function setUp(): void { Registry::$items = []; }
static はテスト間で状態が引き継がれるため、実行順によって結果が変わるテストの原因になります。共有したい値は、コンストラクタで渡す(依存注入)ほうが扱いやすくなります。
関連
- staticについて — 親カテゴリ
- static関数
- スコープ
- 定数
- 変数
- スーパーグローバル変数
子ページ
子ページはありません
同階層のページ
- static変数
- static関数
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09