PHPでファイル操作やデータベース接続、画像処理などを行う際、「この変数はリソース型なの?」という判定が必要になる場面があります。そんな時に重要な役割を果たすのがis_resource関数です。この記事では、is_resource関数の基本的な使い方から実践的な活用方法まで、初心者にも分かりやすく解説します。
is_resource関数とは?
is_resource関数は、指定された変数がリソース型であるかどうかを判定するPHPの組み込み関数です。リソース型とは、外部リソース(ファイル、データベース接続、画像データなど)への参照を保持する特殊なPHPの変数型です。
基本的な構文
bool is_resource(mixed $value)
パラメータ:
$value
:チェックしたい値
戻り値:
true
:値がリソース型の場合false
:値がリソース型以外の場合
リソース型の基本理解
リソース型とは?
リソース型は、PHPの基本的なデータ型(整数、文字列、配列など)とは異なり、外部システムとの接続や特別なデータ構造を表現するために使用されます。
<?php
// ファイルリソース
$file = fopen('example.txt', 'r');
var_dump(is_resource($file)); // bool(true)
var_dump(gettype($file)); // string(8) "resource"
// データベース接続リソース(MySQLi)
$mysqli = new mysqli('localhost', 'user', 'pass', 'database');
$result = $mysqli->query('SELECT * FROM users');
var_dump(is_resource($result)); // bool(false) - MySQLiはオブジェクト
// cURLリソース
$curl = curl_init();
var_dump(is_resource($curl)); // bool(true)
// 画像リソース
$image = imagecreate(100, 100);
var_dump(is_resource($image)); // bool(true)
?>
基本的な使用例
シンプルなリソースチェック
<?php
function checkResourceType($value) {
if (is_resource($value)) {
echo "これはリソース型です: " . get_resource_type($value) . "\n";
} else {
echo "これはリソース型ではありません: " . gettype($value) . "\n";
}
}
// 各種リソースのテスト
$file = fopen('test.txt', 'w');
$curl = curl_init();
$image = imagecreate(50, 50);
$string = "Hello World";
$array = [1, 2, 3];
checkResourceType($file); // これはリソース型です: stream
checkResourceType($curl); // これはリソース型です: curl
checkResourceType($image); // これはリソース型です: gd
checkResourceType($string); // これはリソース型ではありません: string
checkResourceType($array); // これはリソース型ではありません: array
// リソースのクリーンアップ
fclose($file);
curl_close($curl);
imagedestroy($image);
?>
get_resource_type()との組み合わせ
<?php
function analyzeResource($resource) {
if (is_resource($resource)) {
$type = get_resource_type($resource);
echo "リソースタイプ: {$type}\n";
switch ($type) {
case 'stream':
echo "ファイルまたはストリームリソースです\n";
break;
case 'curl':
echo "cURLリソースです\n";
break;
case 'gd':
echo "画像リソースです\n";
break;
case 'mysql link':
echo "MySQLデータベース接続です\n";
break;
default:
echo "その他のリソースです\n";
}
} else {
echo "リソースではありません\n";
}
}
// テスト
$resources = [
fopen('php://memory', 'r+'),
curl_init(),
imagecreate(10, 10),
"not a resource"
];
foreach ($resources as $index => $resource) {
echo "リソース {$index}: ";
analyzeResource($resource);
echo "---\n";
}
?>
実践的な活用シーン
1. ファイル操作での安全性チェック
<?php
class FileManager {
private $fileHandle;
public function openFile($filename, $mode = 'r') {
$this->fileHandle = fopen($filename, $mode);
if (!is_resource($this->fileHandle)) {
throw new RuntimeException("ファイルを開けませんでした: {$filename}");
}
return $this;
}
public function readLine() {
if (!is_resource($this->fileHandle)) {
throw new RuntimeException("有効なファイルハンドルがありません");
}
return fgets($this->fileHandle);
}
public function writeData($data) {
if (!is_resource($this->fileHandle)) {
throw new RuntimeException("有効なファイルハンドルがありません");
}
return fwrite($this->fileHandle, $data);
}
public function closeFile() {
if (is_resource($this->fileHandle)) {
fclose($this->fileHandle);
$this->fileHandle = null;
}
}
public function __destruct() {
$this->closeFile();
}
}
// 使用例
try {
$fileManager = new FileManager();
$fileManager->openFile('example.txt', 'w+');
$fileManager->writeData("Hello, World!\n");
$fileManager->writeData("This is a test file.\n");
$fileManager->closeFile();
echo "ファイル操作が完了しました\n";
} catch (RuntimeException $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
?>
2. cURLリソースの管理
<?php
class HttpClient {
private $curlHandle;
public function __construct() {
$this->curlHandle = curl_init();
if (!is_resource($this->curlHandle)) {
throw new RuntimeException("cURLリソースの初期化に失敗しました");
}
// デフォルト設定
curl_setopt_array($this->curlHandle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false,
]);
}
public function get($url) {
if (!is_resource($this->curlHandle)) {
throw new RuntimeException("無効なcURLリソースです");
}
curl_setopt($this->curlHandle, CURLOPT_URL, $url);
curl_setopt($this->curlHandle, CURLOPT_HTTPGET, true);
$response = curl_exec($this->curlHandle);
if ($response === false) {
throw new RuntimeException("cURLエラー: " . curl_error($this->curlHandle));
}
return $response;
}
public function post($url, $data) {
if (!is_resource($this->curlHandle)) {
throw new RuntimeException("無効なcURLリソースです");
}
curl_setopt_array($this->curlHandle, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
]);
$response = curl_exec($this->curlHandle);
if ($response === false) {
throw new RuntimeException("cURLエラー: " . curl_error($this->curlHandle));
}
return $response;
}
public function getInfo() {
if (!is_resource($this->curlHandle)) {
return [];
}
return curl_getinfo($this->curlHandle);
}
public function __destruct() {
if (is_resource($this->curlHandle)) {
curl_close($this->curlHandle);
}
}
}
// 使用例
try {
$client = new HttpClient();
$response = $client->get('https://api.example.com/data');
$info = $client->getInfo();
echo "HTTPステータス: " . $info['http_code'] . "\n";
echo "レスポンス長: " . strlen($response) . " bytes\n";
} catch (RuntimeException $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
?>
3. 画像処理での利用
<?php
class ImageProcessor {
private $imageResource;
public function createImage($width, $height) {
$this->imageResource = imagecreatetruecolor($width, $height);
if (!is_resource($this->imageResource)) {
throw new RuntimeException("画像リソースの作成に失敗しました");
}
return $this;
}
public function loadImage($filename) {
$info = getimagesize($filename);
if ($info === false) {
throw new InvalidArgumentException("無効な画像ファイルです: {$filename}");
}
switch ($info[2]) {
case IMAGETYPE_JPEG:
$this->imageResource = imagecreatefromjpeg($filename);
break;
case IMAGETYPE_PNG:
$this->imageResource = imagecreatefrompng($filename);
break;
case IMAGETYPE_GIF:
$this->imageResource = imagecreatefromgif($filename);
break;
default:
throw new InvalidArgumentException("サポートされていない画像形式です");
}
if (!is_resource($this->imageResource)) {
throw new RuntimeException("画像の読み込みに失敗しました: {$filename}");
}
return $this;
}
public function resize($newWidth, $newHeight) {
if (!is_resource($this->imageResource)) {
throw new RuntimeException("画像リソースがありません");
}
$originalWidth = imagesx($this->imageResource);
$originalHeight = imagesy($this->imageResource);
$newImage = imagecreatetruecolor($newWidth, $newHeight);
if (!is_resource($newImage)) {
throw new RuntimeException("リサイズ用画像の作成に失敗しました");
}
imagecopyresampled(
$newImage,
$this->imageResource,
0, 0, 0, 0,
$newWidth, $newHeight,
$originalWidth, $originalHeight
);
imagedestroy($this->imageResource);
$this->imageResource = $newImage;
return $this;
}
public function saveAs($filename, $quality = 90) {
if (!is_resource($this->imageResource)) {
throw new RuntimeException("画像リソースがありません");
}
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
switch ($extension) {
case 'jpg':
case 'jpeg':
imagejpeg($this->imageResource, $filename, $quality);
break;
case 'png':
imagepng($this->imageResource, $filename);
break;
case 'gif':
imagegif($this->imageResource, $filename);
break;
default:
throw new InvalidArgumentException("サポートされていない保存形式です: {$extension}");
}
return $this;
}
public function __destruct() {
if (is_resource($this->imageResource)) {
imagedestroy($this->imageResource);
}
}
}
// 使用例
try {
$processor = new ImageProcessor();
$processor->createImage(200, 200)
->saveAs('created_image.png');
echo "画像処理が完了しました\n";
} catch (Exception $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
?>
リソース管理のベストプラクティス
1. リソースリークの防止
<?php
class ResourceManager {
private $resources = [];
public function addResource($resource, $name = null) {
if (!is_resource($resource)) {
throw new InvalidArgumentException("有効なリソースを指定してください");
}
$key = $name ?: uniqid('resource_');
$this->resources[$key] = [
'resource' => $resource,
'type' => get_resource_type($resource),
'created' => time()
];
return $key;
}
public function getResource($key) {
if (!isset($this->resources[$key])) {
throw new InvalidArgumentException("リソースが見つかりません: {$key}");
}
$resource = $this->resources[$key]['resource'];
if (!is_resource($resource)) {
unset($this->resources[$key]);
throw new RuntimeException("リソースが無効になっています: {$key}");
}
return $resource;
}
public function closeResource($key) {
if (!isset($this->resources[$key])) {
return false;
}
$resourceData = $this->resources[$key];
$resource = $resourceData['resource'];
if (is_resource($resource)) {
$type = $resourceData['type'];
switch ($type) {
case 'stream':
fclose($resource);
break;
case 'curl':
curl_close($resource);
break;
case 'gd':
imagedestroy($resource);
break;
}
}
unset($this->resources[$key]);
return true;
}
public function closeAll() {
foreach (array_keys($this->resources) as $key) {
$this->closeResource($key);
}
}
public function listResources() {
$list = [];
foreach ($this->resources as $key => $data) {
$list[$key] = [
'type' => $data['type'],
'valid' => is_resource($data['resource']),
'age' => time() - $data['created']
];
}
return $list;
}
public function __destruct() {
$this->closeAll();
}
}
// 使用例
$manager = new ResourceManager();
try {
// 複数のリソースを管理
$fileKey = $manager->addResource(fopen('test.txt', 'w'), 'testfile');
$curlKey = $manager->addResource(curl_init(), 'httpclient');
$imageKey = $manager->addResource(imagecreate(100, 100), 'thumbnail');
// リソースの使用
$file = $manager->getResource($fileKey);
fwrite($file, "Hello World!");
// リソースの状態確認
print_r($manager->listResources());
// 個別にクローズ
$manager->closeResource($fileKey);
echo "リソース管理が完了しました\n";
} catch (Exception $e) {
echo "エラー: " . $e->getMessage() . "\n";
}
?>
2. リソースの自動クリーンアップ
<?php
class AutoCleanupResource {
private $resource;
private $cleanupCallback;
public function __construct($resource, callable $cleanupCallback = null) {
if (!is_resource($resource)) {
throw new InvalidArgumentException("有効なリソースを指定してください");
}
$this->resource = $resource;
$this->cleanupCallback = $cleanupCallback;
}
public function getResource() {
if (!is_resource($this->resource)) {
throw new RuntimeException("リソースが無効です");
}
return $this->resource;
}
public function isValid() {
return is_resource($this->resource);
}
public function getType() {
return is_resource($this->resource) ? get_resource_type($this->resource) : null;
}
public function cleanup() {
if (is_resource($this->resource)) {
if ($this->cleanupCallback) {
call_user_func($this->cleanupCallback, $this->resource);
} else {
$this->defaultCleanup();
}
$this->resource = null;
}
}
private function defaultCleanup() {
$type = get_resource_type($this->resource);
switch ($type) {
case 'stream':
fclose($this->resource);
break;
case 'curl':
curl_close($this->resource);
break;
case 'gd':
imagedestroy($this->resource);
break;
}
}
public function __destruct() {
$this->cleanup();
}
}
// 使用例
function customCleanup($resource) {
echo "カスタムクリーンアップを実行中...\n";
fclose($resource);
}
$fileResource = new AutoCleanupResource(
fopen('test.txt', 'w'),
'customCleanup'
);
$curlResource = new AutoCleanupResource(curl_init());
echo "ファイルリソースタイプ: " . $fileResource->getType() . "\n";
echo "cURLリソースタイプ: " . $curlResource->getType() . "\n";
// スコープから外れると自動的にクリーンアップされる
?>
古いリソースと新しいオブジェクトの違い
MySQLiの例
<?php
// 古いmysql拡張(PHP 7.0で削除済み)
// $connection = mysql_connect('localhost', 'user', 'pass');
// var_dump(is_resource($connection)); // bool(true)
// 新しいMySQLi(オブジェクト指向)
$mysqli = new mysqli('localhost', 'user', 'pass', 'database');
var_dump(is_resource($mysqli)); // bool(false) - オブジェクトです
// PDO(オブジェクト指向)
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
var_dump(is_resource($pdo)); // bool(false) - オブジェクトです
// 判定の仕方
function checkDatabaseConnection($connection) {
if (is_resource($connection)) {
echo "古いmysql拡張のリソースです\n";
} elseif ($connection instanceof mysqli) {
echo "MySQLiオブジェクトです\n";
} elseif ($connection instanceof PDO) {
echo "PDOオブジェクトです\n";
} else {
echo "不明な接続タイプです\n";
}
}
checkDatabaseConnection($mysqli);
checkDatabaseConnection($pdo);
?>
デバッグとトラブルシューティング
リソースの詳細分析
<?php
function debugResource($value, $name = 'Unknown') {
echo "=== リソース分析: {$name} ===\n";
echo "値: " . var_export($value, true) . "\n";
echo "型: " . gettype($value) . "\n";
echo "is_resource: " . (is_resource($value) ? 'true' : 'false') . "\n";
if (is_resource($value)) {
echo "リソースタイプ: " . get_resource_type($value) . "\n";
// リソース固有の情報
$type = get_resource_type($value);
switch ($type) {
case 'stream':
$meta = stream_get_meta_data($value);
echo "ストリーム情報:\n";
echo " - URI: " . $meta['uri'] . "\n";
echo " - モード: " . $meta['mode'] . "\n";
echo " - 読み取り可能: " . ($meta['seekable'] ? 'Yes' : 'No') . "\n";
break;
case 'curl':
$info = curl_getinfo($value);
echo "cURL情報:\n";
echo " - URL: " . ($info['url'] ?: 'Not set') . "\n";
echo " - HTTPコード: " . $info['http_code'] . "\n";
break;
case 'gd':
echo "GD画像情報:\n";
echo " - 幅: " . imagesx($value) . "px\n";
echo " - 高さ: " . imagesy($value) . "px\n";
break;
}
}
echo "\n";
}
// テスト用リソース
$resources = [
'file' => fopen('php://memory', 'r+'),
'curl' => curl_init(),
'image' => imagecreate(50, 50),
'string' => 'not a resource',
'null' => null
];
foreach ($resources as $name => $resource) {
debugResource($resource, $name);
}
// クリーンアップ
fclose($resources['file']);
curl_close($resources['curl']);
imagedestroy($resources['image']);
?>
メモリリークの検出
<?php
class ResourceLeakDetector {
private $initialMemory;
private $resources = [];
public function __construct() {
$this->initialMemory = memory_get_usage();
}
public function trackResource($resource, $name) {
if (!is_resource($resource)) {
throw new InvalidArgumentException("リソースではありません");
}
$this->resources[$name] = [
'resource' => $resource,
'type' => get_resource_type($resource),
'memory_at_creation' => memory_get_usage()
];
}
public function checkLeaks() {
$currentMemory = memory_get_usage();
$memoryIncrease = $currentMemory - $this->initialMemory;
echo "=== メモリリーク検出 ===\n";
echo "初期メモリ: " . $this->formatBytes($this->initialMemory) . "\n";
echo "現在のメモリ: " . $this->formatBytes($currentMemory) . "\n";
echo "増加量: " . $this->formatBytes($memoryIncrease) . "\n";
$activeResources = 0;
foreach ($this->resources as $name => $data) {
if (is_resource($data['resource'])) {
$activeResources++;
echo "アクティブリソース: {$name} ({$data['type']})\n";
}
}
echo "アクティブリソース数: {$activeResources}\n";
if ($memoryIncrease > 1024 * 1024) { // 1MB以上
echo "⚠️ メモリリークの可能性があります\n";
}
echo "\n";
}
private function formatBytes($bytes) {
$units = ['B', 'KB', 'MB', 'GB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, 2) . ' ' . $units[$pow];
}
}
// 使用例
$detector = new ResourceLeakDetector();
// リソースを作成・追跡
for ($i = 0; $i < 100; $i++) {
$file = fopen('php://memory', 'r+');
$detector->trackResource($file, "file_{$i}");
// 一部のリソースを意図的に閉じない(リーク)
if ($i % 10 !== 0) {
fclose($file);
}
}
$detector->checkLeaks();
?>
まとめ
is_resource関数は、PHPでリソース型の判定を行うための重要な関数です。ファイル操作、ネットワーク通信、画像処理など、外部リソースを扱う際には必須の機能となります。
重要なポイント:
- リソース型は外部リソースへの参照を保持する特殊な型
- 適切なリソース管理でメモリリークを防ぐ
- 新しいPHPではオブジェクト指向のAPIが推奨される
- リソースの自動クリーンアップ機能を実装することが重要
リソース管理はアプリケーションの安定性とパフォーマンスに直結します。この記事で紹介した例を参考に、適切なリソース管理を実装してください。
この記事がPHP開発の参考になれば幸いです。他にも疑問点があれば、コメントやお問い合わせフォームからお気軽にご質問ください。