Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】SessionHandlerInterface::gc()メソッドの使い方

gcメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

gcメソッドは、セッションの有効期限が切れたデータをストレージから削除するガベージコレクション処理を実行するメソッドです。このメソッドは、PHPの標準セッションメカニズムとは異なる方法でセッションを管理したい場合に利用するSessionHandlerInterfaceの一部として定義されます。

システムエンジニアがWebアプリケーションを開発する際、ユーザーのログイン状態やカートの中身といった情報をサーバー側に一時的に保存する「セッション」という仕組みを利用します。しかし、これらのセッションデータはいつまでも保存しておくわけにはいきません。ユーザーがログアウトしたり、一定時間アクセスがなかったりすると、セッションは「期限切れ」となり、不要なデータとして残ってしまいます。

gcメソッドは、そのような期限切れになったセッションデータを自動的に削除し、サーバーのリソースを解放するために呼び出されます。このメソッドは、$max_lifetimeという整数値の引数を受け取ります。この$max_lifetimeは、セッションが有効であると見なされる最大秒数を表しており、メソッドの実装ではこの値よりも古いセッションデータを削除するロジックを記述します。

PHPの内部で設定された確率と周期に基づき、セッションが開始される際にこのgcメソッドが呼び出されることがあります。開発者はSessionHandlerInterfaceを実装する際に、ファイルシステム、データベース、またはキャッシュサーバーなど、自身のアプリケーションが利用するセッションストレージから、どのようにして期限切れセッションを効率的に見つけて削除するかをこのメソッド内に実装します。これにより、セッションストレージの肥大化を防ぎ、アプリケーションのパフォーマンスとセキュリティを維持することができます。戻り値は、削除に成功した場合はtrue、失敗した場合はfalse、または削除されたセッションの数を返すことが期待されます。

構文(syntax)

1<?php
2
3interface SessionHandlerInterface
4{
5    public function gc(int $max_lifetime): int;
6}

引数(parameters)

int $max_lifetime

  • int $max_lifetime: セッションデータを削除する最大生存期間を秒単位で指定する整数

戻り値(return)

int

gc メソッドは、ガベージコレクション(不要になったセッションデータの削除)が正常に実行されたかどうかを示す整数値を返します。成功した場合は true の意味合いを持つ値、失敗した場合は false の意味合いを持つ値が返されます。

サンプルコード

PHPセッションGCのタイミングを解説する

1<?php
2
3/**
4 * MyCustomSessionHandler class
5 * Implements SessionHandlerInterface to provide custom session storage logic.
6 * This example uses file-based storage in a temporary directory.
7 */
8class MyCustomSessionHandler implements SessionHandlerInterface
9{
10    private string $savePath;
11
12    /**
13     * Initializes the session handler.
14     * Called when a session is opened (e.g., by session_start()).
15     * @param string $path The path where session data should be stored.
16     * @param string $name The session name.
17     * @return bool True on success, false on failure.
18     */
19    public function open(string $path, string $name): bool
20    {
21        $this->savePath = $path;
22        if (!is_dir($this->savePath)) {
23            mkdir($this->savePath, 0777, true); // Create directory if it doesn't exist
24        }
25        return true;
26    }
27
28    /**
29     * Closes the session handler.
30     * Called when a session is closed (e.g., by session_write_close() or script termination).
31     * @return bool True on success, false on failure.
32     */
33    public function close(): bool
34    {
35        // For file-based sessions, usually nothing specific to do here.
36        return true;
37    }
38
39    /**
40     * Reads session data.
41     * Called by PHP to retrieve session data for a given session ID.
42     * @param string $id The session ID.
43     * @return string The session data (serialized), or an empty string if not found.
44     */
45    public function read(string $id): string
46    {
47        $file = $this->savePath . '/sess_' . $id . '.txt';
48        if (file_exists($file)) {
49            // Update the last modification time to mark the session as recently accessed.
50            // This prevents it from being immediately garbage collected.
51            touch($file); 
52            return (string)file_get_contents($file);
53        }
54        return '';
55    }
56
57    /**
58     * Writes session data.
59     * Called by PHP to save session data for a given session ID.
60     * @param string $id The session ID.
61     * @param string $data The serialized session data.
62     * @return bool True on success, false on failure.
63     */
64    public function write(string $id, string $data): bool
65    {
66        $file = $this->savePath . '/sess_' . $id . '.txt';
67        return file_put_contents($file, $data) !== false;
68    }
69
70    /**
71     * Destroys a session.
72     * Called by PHP when a session is explicitly destroyed (e.g., by session_destroy()).
73     * @param string $id The session ID to destroy.
74     * @return bool True on success, false on failure.
75     */
76    public function destroy(string $id): bool
77    {
78        $file = $this->savePath . '/sess_' . $id . '.txt';
79        if (file_exists($file)) {
80            return unlink($file); // Delete the session file
81        }
82        return true;
83    }
84
85    /**
86     * Garbage collection handler.
87     * This method is called probabilistically by PHP during session_start().
88     * Its purpose is to delete old, expired session data.
89     * @param int $max_lifetime The maximum time in seconds that a session can be inactive before it's considered expired.
90     * @return int The number of sessions deleted.
91     */
92    public function gc(int $max_lifetime): int
93    {
94        $deletedCount = 0;
95        echo "  [GC] Running garbage collection with max_lifetime: {$max_lifetime} seconds.\n";
96
97        // Iterate over all session files in the designated save path
98        foreach (glob($this->savePath . '/sess_*.txt') as $file) {
99            if (file_exists($file)) {
100                // Get the last modification time of the session file
101                $lastModified = filemtime($file);
102                if ($lastModified === false) {
103                    continue; // Skip if unable to get file modification time
104                }
105
106                // Calculate the age of the session file
107                $fileAge = time() - $lastModified;
108
109                // If the session file's age is greater than the configured max_lifetime, delete it.
110                if ($fileAge > $max_lifetime) {
111                    unlink($file); // Delete the expired session file
112                    $deletedCount++;
113                    echo "  [GC] Deleted old session file: " . basename($file) . " (Age: {$fileAge}s)\n";
114                }
115            }
116        }
117        return $deletedCount; // Return the total count of deleted sessions
118    }
119}
120
121// --- Demonstration of MyCustomSessionHandler and gc() timing ---
122
123// 1. Setup a temporary directory for session files
124$sessionSavePath = sys_get_temp_dir() . '/php_beginner_sessions_' . uniqid();
125if (!is_dir($sessionSavePath)) {
126    mkdir($sessionSavePath, 0777, true);
127}
128echo "Temporary session save path: " . $sessionSavePath . "\n\n";
129
130// 2. Create some dummy session files to illustrate garbage collection:
131//    - Two "old" sessions that should be collected by gc().
132//    - One "recent" session that should remain.
133$oldSessionId1 = 'old_session_one';
134$oldSessionFile1 = $sessionSavePath . '/sess_' . $oldSessionId1 . '.txt';
135file_put_contents($oldSessionFile1, 'This is old session data 1.');
136// Set its modification time far in the past (e.g., 2 hours ago)
137touch($oldSessionFile1, time() - 7200);
138
139$oldSessionId2 = 'old_session_two';
140$oldSessionFile2 = $sessionSavePath . '/sess_' . $oldSessionId2 . '.txt';
141file_put_contents($oldSessionFile2, 'This is old session data 2.');
142// Set its modification time moderately in the past (e.g., 1 hour ago)
143touch($oldSessionFile2, time() - 3600);
144
145$recentSessionId = 'recent_session_abc';
146$recentSessionFile = $sessionSavePath . '/sess_' . $recentSessionId . '.txt';
147file_put_contents($recentSessionFile, 'This is recent session data.');
148// Set its modification time very recently (e.g., 5 seconds ago)
149touch($recentSessionFile, time() - 5);
150
151echo "--- Initial state of session files in " . basename($sessionSavePath) . " ---\n";
152foreach (glob($sessionSavePath . '/sess_*.txt') as $file) {
153    echo "  - " . basename($file) . " (Modified: " . date('Y-m-d H:i:s', filemtime($file)) . ")\n";
154}
155echo "\n";
156
157// 3. Instantiate and register our custom session handler
158$handler = new MyCustomSessionHandler();
159session_set_save_handler($handler, true); // `true` registers it as the default handler
160
161// 4. Configure session settings for GC demonstration:
162//    - `session.gc_maxlifetime`: How old (in seconds) a session can be before GC considers it.
163//    - `session.gc_probability` & `session.gc_divisor`: Controls the probability of gc() being called.
164//      Setting these to 1/1 ensures gc() will run every time session_start() is called for this example.
165//      (In production, these are typically higher like 1/1000 or configured in php.ini).
166ini_set('session.gc_maxlifetime', 30); // Sessions older than 30 seconds will be collected
167ini_set('session.gc_probability', 1);
168ini_set('session.gc_divisor', 1);
169
170// Set the session save path to our temporary directory for the custom handler
171session_save_path($sessionSavePath);
172
173echo "--- Starting session and observing gc() timing ---\n";
174echo "Current 'session.gc_maxlifetime' is set to " . ini_get('session.gc_maxlifetime') . " seconds.\n";
175echo "Garbage Collection probability is " . ini_get('session.gc_probability') . "/" . ini_get('session.gc_divisor') . " (ensures gc() runs).\n";
176echo "The custom `MyCustomSessionHandler::gc()` method will be called by PHP internally "
177    . "during the `session_start()` process if the probability check passes.\n";
178
179// 5. Start a session. This is the point where PHP might trigger gc().
180session_start();
181
182// Store some data in the current session (this creates a new session file or updates an existing one)
183$_SESSION['user_id'] = 456;
184$_SESSION['username'] = 'beginner_se';
185$_SESSION['message'] = 'Welcome to your custom session!';
186
187echo "\nCurrent session started. Session ID: " . session_id() . "\n";
188echo "Session data stored for the current active session.\n";
189
190// 6. Close the session. This ensures any pending write operations are completed.
191session_write_close();
192
193echo "\n--- State of session files AFTER session_start() and potential GC ---\n";
194echo "Notice that old session files (older than " . ini_get('session.gc_maxlifetime') . "s) "
195    . "should have been cleaned up.\n";
196foreach (glob($sessionSavePath . '/sess_*.txt') as $file) {
197    echo "  - " . basename($file) . " (Modified: " . date('Y-m-d H:i:s', filemtime($file)) . ")\n";
198}
199
200// 7. Clean up the temporary session directory
201if (is_dir($sessionSavePath)) {
202    foreach (glob($sessionSavePath . '/*') as $file) {
203        unlink($file);
204    }
205    rmdir($sessionSavePath);
206    echo "\nTemporary session directory '" . basename($sessionSavePath) . "' cleaned up.\n";
207}
208
209?>

PHPのSessionHandlerInterface::gcメソッドは、カスタムセッションハンドラにおいて、期限切れのセッションデータを整理・削除する役割を持ちます。このメソッドはint $max_lifetimeという引数を受け取ります。これは、セッションが非アクティブと見なされるまでの最大秒数を指定し、この期間を超えてアクセスされていないセッションデータが削除の対象となります。メソッドは削除したセッションの総数をintで返します。

gcメソッドは、PHPのセッションが開始される際、具体的にはsession_start()関数が実行されるタイミングで、PHPの設定(session.gc_probabilitysession.gc_divisor)に基づいて確率的に呼び出されます。これにより、セッションが開始されるたびに、古いデータが自動的にクリーンアップされる機会が与えられます。

サンプルコードのMyCustomSessionHandlerクラスは、SessionHandlerInterfaceを実装し、ファイルシステムを利用してセッションを管理する例です。その中のgcメソッドは、引数で渡された$max_lifetimeよりも最終更新日時が古いセッションファイルを検索し、削除する具体的な処理を実装しています。コードのデモンストレーション部分では、意図的に作成した古いセッションファイル群と、session.gc_maxlifetimeを短く設定した上でsession_start()を実行することで、gcメソッドが実際に機能し、期限切れのファイルを自動的にクリーンアップする様子を示しています。これにより、セッションの有効期限管理の仕組みと、gcメソッドが果たす重要な役割を理解できます。

gcメソッドは、開発者が直接呼び出すのではなく、session_start()実行時にPHPが内部で確率的に呼び出すものです。主な役割は、session.gc_maxlifetime設定値で指定された秒数よりも古いセッションデータを削除することです。サンプルコードのreadメソッドでセッションファイルの最終更新日時を更新しているように、セッションがアクティブである間は有効期限が延長されるよう適切に実装しないと、使用中のセッションが誤って削除される可能性がありますので注意が必要です。また、本番環境ではsession.gc_probabilitysession.gc_divisorの設定によりgcの実行頻度を調整し、サーバー負荷を考慮することが重要です。サンプルではデモンストレーションのため強制実行していますが、一般的な運用では確率を低く設定します。ファイル以外でセッションを保存する場合も、このgcメソッド内で該当ストレージから古いデータを削除するロジックを実装してください。

PHPカスタムセッションハンドラでGCを実装する

1<?php
2
3/**
4 * カスタムセッションハンドラの実装例。
5 * SessionHandlerInterface を通じて、PHPのセッション管理をファイルシステムで行います。
6 * このクラスは、SessionHandlerInterface が要求するすべてのメソッドを実装しており、
7 * 特に gc() (ガーベージコレクション) メソッドの動作に焦点を当てています。
8 *
9 * システムエンジニアを目指す初心者向けに、セッションデータの寿命管理の概念を理解できるようにします。
10 */
11class MySessionHandler implements SessionHandlerInterface
12{
13    private string $savePath;
14
15    /**
16     * セッションを開きます。
17     * セッションデータが保存されるディレクトリパスを設定し、必要であれば作成します。
18     */
19    public function open(string $path, string $alias): bool
20    {
21        $this->savePath = $path;
22        if (!is_dir($this->savePath)) {
23            mkdir($this->savePath, 0777, true);
24        }
25        return true;
26    }
27
28    /**
29     * セッションを閉じます。
30     */
31    public function close(): bool
32    {
33        return true;
34    }
35
36    /**
37     * 指定されたセッションIDのデータを読み込みます。
38     * ファイルが存在しない場合は空文字列を返します。
39     */
40    public function read(string $id): string|false
41    {
42        $file = $this->savePath . '/sess_' . $id;
43        if (file_exists($file)) {
44            return file_get_contents($file);
45        }
46        return '';
47    }
48
49    /**
50     * 指定されたセッションIDにデータを書き込みます。
51     */
52    public function write(string $id, string $data): bool
53    {
54        $file = $this->savePath . '/sess_' . $id;
55        return file_put_contents($file, $data) !== false;
56    }
57
58    /**
59     * 指定されたセッションIDのセッションデータを削除します。
60     */
61    public function destroy(string $id): bool
62    {
63        $file = $this->savePath . '/sess_' . $id;
64        if (file_exists($file)) {
65            return unlink($file);
66        }
67        return true;
68    }
69
70    /**
71     * セッションのガーベージコレクション (GC) を実行します。
72     * $max_lifetime で指定された期間よりも古いセッションファイルを削除します。
73     * このメソッドはPHPの内部で、session_start() などのセッション初期化時に確率的に呼び出されます。
74     *
75     * @param int $max_lifetime セッションの最大有効期間 (秒)。この期間より古いデータが削除対象。
76     * @return int 実際に削除されたセッションファイルの数。
77     */
78    public function gc(int $max_lifetime): int
79    {
80        $deletedCount = 0;
81        $now = time();
82        
83        // セッションファイルが保存されているディレクトリ内のファイルを全て取得
84        $files = glob($this->savePath . '/sess_*');
85        if ($files === false) {
86            return 0;
87        }
88
89        foreach ($files as $file) {
90            // ファイルが存在し、かつ最終変更時刻が現在時刻から $max_lifetime 秒以上経過している場合
91            if (file_exists($file) && filemtime($file) + $max_lifetime < $now) {
92                unlink($file); // 古いセッションファイルを削除
93                $deletedCount++;
94            }
95        }
96        
97        return $deletedCount;
98    }
99}
100
101// --- サンプルコード実行部分 ---
102
103// セッションデータ用の一時ディレクトリパスを生成 (他のプロセスと干渉しないようユニークに)
104$sessionSavePath = sys_get_temp_dir() . '/php_custom_sessions_' . uniqid();
105if (!is_dir($sessionSavePath)) {
106    mkdir($sessionSavePath, 0777, true);
107    echo "セッション保存ディレクトリを作成しました: " . $sessionSavePath . "\n";
108}
109
110// カスタムセッションハンドラのインスタンスを作成し、PHPのセッション管理に登録
111$handler = new MySessionHandler();
112session_set_save_handler($handler, true); // true はスクリプト終了時に自動で close() を呼び出す設定
113
114// PHPのセッション保存パスをカスタムハンドラが使用するパスに設定
115session_save_path($sessionSavePath);
116
117// セッションを開始。これにより MySessionHandler::open() や MySessionHandler::read() が呼ばれます。
118session_start();
119
120// セッションデータを設定・表示
121if (!isset($_SESSION['visits'])) {
122    $_SESSION['visits'] = 1;
123    echo "初めての訪問です。現在のセッションID: " . session_id() . "\n";
124} else {
125    $_SESSION['visits']++;
126    echo "訪問回数: " . $_SESSION['visits'] . "回。現在のセッションID: " . session_id() . "\n";
127}
128
129// セッションデータを保存し、セッションを終了します。
130// これにより MySessionHandler::write() と MySessionHandler::close() が呼び出されます。
131session_write_close();
132
133// === gc() メソッドの動作デモンストレーション ===
134// 通常、gc()はPHPがセッション開始時に確率的に自動呼び出ししますが、
135// ここでは動作確認のため、手動で呼び出し、削除される様子を示します。
136
137$currentSessionFile = $sessionSavePath . '/sess_' . session_id();
138
139if (file_exists($currentSessionFile)) {
140    echo "\nセッションファイルが存在します: " . $currentSessionFile . "\n";
141    // GCで削除されるように、このファイルの最終更新時刻を意図的に古くします (例: 100秒前)
142    touch($currentSessionFile, time() - 100); 
143    echo "セッションファイルの最終更新時刻を意図的に古くしました。\n";
144} else {
145    echo "\nセッションファイルが見つかりませんでした。\n";
146}
147
148// $max_lifetime を短く設定し (例: 5秒)、gc() を呼び出します。
149// これにより、5秒より古い (ここでは意図的に古くした) セッションファイルが削除対象となります。
150$testMaxLifetime = 5; 
151echo "gc() メソッドを呼び出し中 (最大生存期間: " . $testMaxLifetime . "秒より古いものを削除)...\n";
152$deletedSessions = $handler->gc($testMaxLifetime);
153echo "削除されたセッションファイルの数: " . $deletedSessions . "\n";
154
155// gc() 実行後、現在のセッションファイルが削除されたかを確認
156if (!file_exists($currentSessionFile)) {
157    echo "現在のセッションファイル (" . $currentSessionFile . ") は削除されました。\n";
158} else {
159    echo "現在のセッションファイル (" . $currentSessionFile . ") は削除されませんでした。\n";
160}
161
162// クリーンアップ: 作成した一時ディレクトリとその中のファイルを削除
163// (本番環境ではセッションデータディレクトリは通常削除しません)
164if (is_dir($sessionSavePath)) {
165    foreach (glob($sessionSavePath . '/*') as $file) {
166        unlink($file);
167    }
168    rmdir($sessionSavePath);
169    echo "セッション保存ディレクトリをクリーンアップしました。\n";
170}
171
172?>

SessionHandlerInterface::gcは、PHPのセッション管理において、期限切れになった古いセッションデータを自動的に削除する「ガーベージコレクション」を実行するメソッドです。ウェブアプリケーションでは、ユーザーの活動が停止したり、有効期限が過ぎたりしたセッションのデータがサーバー上に残ってしまうことがあります。このメソッドは、そうした不要なデータを定期的にクリーンアップし、サーバーのリソースを効率的に保つ重要な役割を担います。

引数$max_lifetimeには、セッションデータの最大有効期間を秒単位で指定します。この期間よりも長く更新されていないセッションデータが、このメソッドによって削除の対象となります。例えば、$max_lifetime3600(1時間)であれば、1時間以上活動のない古いセッションファイルは削除されます。

戻り値はint型で、実際に削除されたセッションデータの数を返します。これにより、一度のガーベージコレクション処理でどれだけの古いセッションがクリーンアップされたかを確認できます。

PHPは通常、session_start()などでセッションが開始される際に、このgcメソッドを内部的に確率で呼び出し、セッションの寿命を管理しています。サンプルコードでは、カスタムセッションハンドラであるMySessionHandlerクラスがSessionHandlerInterfaceを実装し、gcメソッド内で、指定された$max_lifetimeに基づき、セッションファイル保存ディレクトリ内の古いファイルを検索して削除する具体的な処理を記述しています。この実装例を通じて、PHPがどのようにセッションの自動清掃を行うか、その仕組みを理解することができます。

PHPのSessionHandlerInterface::gc()メソッドは、セッション開始時にPHPによって自動的かつ確率的に呼び出されるため、通常は開発者が手動で実行する必要はありません。このメソッドは、引数$max_lifetimeで指定された最大有効期間を過ぎた古いセッションデータを削除する役割を持ちます。カスタムセッションハンドラを利用する際は、セッションファイルを保存するディレクトリに適切な読み書き権限を設定することが非常に重要です。権限不足はセッション管理の障害となりますのでご注意ください。また、「php gc_collect_cycles」はPHPのメモリ管理における循環参照のガベージコレクションであり、本メソッドのようにファイルやデータベース上のセッションデータを削除する役割とは目的が異なりますので混同しないようにしてください。このサンプルはファイルベースですが、データベースなど他のストレージを利用する場合も同様にgc()の実装が必要です。

関連コンテンツ