PHP 入門

PHP データ型変換

PHP はダイナミックタイピング(動的型付け)言語です。これは、バリアブル(変数)タイプ(型)を明示的に宣言する必要がなく、実行時に代入された値に基づいて自動的に決定されることを意味します。この動的な特性により、2 つの重要な挙動が発生します。それが「型ジャグリング(Type Juggling / 自動型変換)」と「型キャスト(Type Casting / 明示的型変換)」です。

1. 型ジャグリング

型ジャグリング(弱型変換とも呼ばれます)とは、PHP がバリアブルが使用されるコンテキスト(文脈)に応じて、値をあるデータタイプから別のタイプへ自動的に変換することを指します。この挙動は、算術演算、ストリングの結合、あるいは論理比較の際によく発生します。PHP は、複数のタイプが混在する操作を成立させるために、一方または両方のオペランド(操作数)を互換性のあるタイプに変換しようと試みます。

1.1 ブーリアン (Boolean) への変換

値がブーリアンのコンテキスト(例:if 文、論理演算子など)で評価される際、PHP は自動的にそれを true または false に変換します。

以下の値は false(偽値) とみなされます:

  • ブーリアンの false
  • インテジャーの 0 およびフロートの 0.0
  • 空のストリング "" およびストリングのゼロ "0"
  • 空のアレイ(配列) []
  • 特殊な値 NULL

これら以外のすべての値(リソースタイプやオブジェクトを含む)は、true とみなされます。

<?php
$isEmptyString = "";
if ($isEmptyString) {
    echo "空のストリングは false とみなされるため、これはプリントされません。";
}

$zeroInteger = 0;
if ($zeroInteger) {
    echo "0 は false とみなされるため、これはプリントされません。";
}

$nonEmptyString = "Hello";
if ($nonEmptyString) {
    echo "'Hello' は true とみなされるため、これがプリントされます。\n"; // 出力:'Hello' は true とみなされるため、これがプリントされます。
}

$oneInteger = 1;
if ($oneInteger) {
    echo "1 は true とみなされるため、これがプリントされます。\n"; // 出力:1 は true とみなされるため、これがプリントされます。
}
?>

1.2 数値 (Integer または Float) への変換

算術演算を実行する場合や数値を表すストリングを比較する場合、PHP は数値以外の値をインテジャー(整数)またはフロート(浮動小数点数)に変換しようとします。

  • ストリングが数値で始まる場合、その先頭の数値部分を抽出して変換します。
  • ストリングが数値で始まらない場合、0 に変換されます。
  • ブーリアンの true1 に、false0 に変換されます。
  • NULL0 に変換されます。
<?php
$stringNumber = "10";
$integerValue = 5;
$result1 = $stringNumber + $integerValue; // "10" が暗黙的にインテジャー 10 に変換されます
echo "結果 1:" . $result1 . "\n"; // 出力:結果 1:15

$stringWithText = "20 apples";
$result2 = $stringWithText + $integerValue; // "20 apples" の先頭の数値を抽出し、インテジャー 20 に変換
echo "結果 2:" . $result2 . "\n"; // 出力:結果 2:25

$stringNonNumeric = "Hello World";
$result3 = $stringNonNumeric + $integerValue; // "Hello World" は数値で始まらないため、0 に変換
echo "結果 3:" . $result3 . "\n"; // 出力:結果 3:5

$booleanTrue = true;
$result4 = $booleanTrue + $integerValue; // true は 1 に変換
echo "結果 4:" . $result4 . "\n"; // 出力:結果 4:6

$nullValue = NULL;
$result5 = $nullValue + $integerValue; // NULL は 0 に変換
echo "結果 5:" . $result5 . "\n"; // 出力:結果 5:5
?>

1.3 ストリング (String) への変換

ドット記号 . オペレータによる結合や、バリアブルがストリングのコンテキストで使用される場合(例:echo による出力)、PHP は他のタイプをストリングに変換します。

  • インテジャーやフロートは、対応する文字列形式に変換されます。
  • ブーリアンの true"1" に、false""(空のストリング)になります。
  • NULL""(空のストリング)になります。
  • アレイは "Array"、オブジェクトは "Object"__toString() メソッドが定義されていない場合)というストリングに変換されます。これは通常、Notice または Warning レベルの警告を発生させます。
<?php
$number = 123;
$string = "数値:" . $number; // 123 が "123" に変換されます
echo $string . "\n"; // 出力:数値:123

$boolean = true;
$stringBoolean = "ステータス:" . $boolean; // true が "1" に変換されます
echo $stringBoolean . "\n"; // 出力:ステータス:1

$null = NULL;
$stringNull = "空の値:" . $null; // NULL が "" に変換されます
echo $stringNull . "\n"; // 出力:空の値:

$array = [1, 2, 3];
// これは Notice 警告を発生させます:Array to string conversion
$stringArray = "データ:" . $array; 
echo $stringArray . "\n"; // 出力:データ:Array
?>

1.4 型ジャグリングの実質的な影響 (よくある罠)

型ジャグリングは PHP のコード記述を柔軟にしますが、「予期しない自動変換」によってバグの原因になることが多々あります。最も典型的な例が比較操作です。

例えば、ゆるやかな比較 == を使用すると、ストリングの "10" はインテジャーの 10 と等しくなり、ストリングの "0" はブーリアンの false と等しくなります。

フォームからのユーザー入力(通常はすべてストリングタイプ)と、データベースから取得したインテジャーの ID を比較するシナリオを考えてみましょう。

<?php
$userInputId = "123"; // フォームから送信されたユーザー ID(常にストリング)
$databaseId = 123;    // データベース内のユーザー ID(インテジャー)

// == を使用したゆるやかな比較
if ($userInputId == $databaseId) {
    echo "ゆるやかな比較:ユーザー ID がマッチしました (true)\n"; // これが出力されます
} else {
    echo "ゆるやかな比較:ユーザー ID がマッチしません (false)\n";
}

// === を使用した厳格な比較
if ($userInputId === $databaseId) {
    echo "厳格な比較:ユーザー ID がマッチしました (true)\n";
} else {
    echo "厳格な比較:ユーザー ID がマッチしません (false)\n"; // これが出力されます
}
?>

上の例では、== が型ジャグリングをトリガーし、"123" をインテジャーの 123 に変換してから比較したため、結果は true になりました。しかし、===(厳格な比較)は値とデータタイプの両方をチェックするため、ストリングの "123" とインテジャーの 123 が完全には同一でないことを正しく識別できます。

2. 型キャスト

型キャストとは、ある値を一つのデータタイプから別のタイプへ明示的に変換することです。PHP が自動的に推測する型ジャグリングとは異なり、キャストはキャストオペレータを使用して、バリアブルを特定のタイプに変換するよう PHP に明確に命令します。これにより、開発者はデータタイプを直接コントロールでき、自動変換による予期せぬバグを効果的に防ぐことができます。

2.1 キャストの実行方法

キャストを行うには、変換したいバリアブルや値の前に、括弧で囲んだターゲットのタイプ名を記述するだけです。

PHP で利用可能なキャストオペレータは以下の通りです:

  • (int) または (integer): インテジャーに変換
  • (float) または (double) または (real): フロートに変換
  • (string): ストリングに変換
  • (bool) または (boolean): ブーリアンに変換
  • (array): アレイに変換
  • (object): オブジェクトに変換
  • (unset): NULL に変換(PHP 7.0 以降はバリアブルに対してのみ。新しいバージョンでは非推奨・削除されているため、知識として留めておくだけで構いません)

2.2 キャストの一般的な例

インテジャー (int) への変換:

  • フロートの小数点以下は切り捨てられます(四捨五入されません)。
  • true1 に、false0 になります。
  • 数値で始まるストリングはその数値になり、それ以外は 0 になります。
<?php
$floatValue = 3.75;
$intValue1 = (int)$floatValue;
echo "フロート 3.75 からインテジャーへ:" . $intValue1 . "\n"; // 出力:3

$booleanValue = true;
$intValue2 = (int)$booleanValue;
echo "ブーリアン true からインテジャーへ:" . $intValue2 . "\n"; // 出力:1

$stringValue = "123 test";
$intValue3 = (int)$stringValue;
echo "ストリング '123 test' からインテジャーへ:" . $intValue3 . "\n"; // 出力:123

$nonNumericString = "hello";
$intValue4 = (int)$nonNumericString;
echo "ストリング 'hello' からインテジャーへ:" . $intValue4 . "\n"; // 出力:0
?>

フロート (float) への変換:
ルールはインテジャーへの変換と似ていますが、結果には小数の精度が保持されます。

<?php
$integerValue = 10;
$floatValue1 = (float)$integerValue;
echo "インテジャー 10 からフロートへ:" . $floatValue1 . "\n"; // 出力:10

$stringValue = "5.99";
$floatValue2 = (float)$stringValue;
echo "ストリング '5.99' からフロートへ:" . $floatValue2 . "\n"; // 出力:5.99

$anotherString = "price 15.50";
$floatValue3 = (float)$anotherString;
echo "ストリング 'price 15.50' からフロートへ:" . $floatValue3 . "\n"; // 出力:0
?>

ストリング (string) への変換:
数値はテキスト形式になり、true"1"false"" になります。

<?php
$number = 42;
$stringValue1 = (string)$number;
echo "数値 42 からストリングへ:'" . $stringValue1 . "' (タイプ:" . gettype($stringValue1) . ")\n"; // 出力:'42' (タイプ:string)

$boolean = false;
$stringValue2 = (string)$boolean;
echo "ブーリアン false からストリングへ:'" . $stringValue2 . "' (タイプ:" . gettype($stringValue2) . ")\n"; // 出力:'' (タイプ:string)

$null = NULL;
$stringValue3 = (string)$null;
echo "NULL からストリングへ:'" . $stringValue3 . "' (タイプ:" . gettype($stringValue3) . ")\n"; // 出力:'' (タイプ:string)

$array = [1, 2];
$stringValue4 = (string)$array; // 結果は "Array" になります
echo "アレイからストリングへ:'" . $stringValue4 . "' (タイプ:" . gettype($stringValue4) . ")\n"; // 出力:'Array' (タイプ:string)
?>

ブーリアン (bool) への変換:

前述の「偽値 (Falsy values)」のルールに従います。

<?php
$intZero = 0;
$boolValue1 = (bool)$intZero;
echo "インテジャー 0 からブーリアンへ:" . var_export($boolValue1, true) . "\n"; // 出力:false

$nonEmptyString = "PHP";
$boolValue2 = (bool)$nonEmptyString;
echo "ストリング 'PHP' からブーリアンへ:" . var_export($boolValue2, true) . "\n"; // 出力:true

$emptyArray = [];
$boolValue3 = (bool)$emptyArray;
echo "空のアレイからブーリアンへ:" . var_export($boolValue3, true) . "\n"; // 出力:false
?>

アレイ (array) への変換:

スカラー値(単一の値)の場合、その値を唯一の要素(インデックス 0)とするアレイになります。

<?php
$number = 123;
$arrayFromInt = (array)$number;
print_r($arrayFromInt);
// 出力:Array ( [0] => 123 )

$string = "hello";
$arrayFromString = (array)$string;
print_r($arrayFromString);
// 出力:Array ( [0] => hello )

$null = NULL;
$arrayFromNull = (array)$null;
print_r($arrayFromNull);
// 出力:Array ( )
?>

オブジェクト (object) への変換:

スカラー値は scalar という名前のプロパティを持つオブジェクトになり、そこに元の値が格納されます。連想配列(キーを持つ配列)の場合、配列のキーがオブジェクトのプロパティ名になります。

<?php
$stringValue = "example";
$objectFromString = (object)$stringValue;
var_dump($objectFromString);
// 出力:object(stdClass)#1 (1) { ["scalar"]=> string(7) "example" }

$associativeArray = ['name' => 'Alice', 'age' => 30];
$objectFromArray = (object)$associativeArray;
var_dump($objectFromArray);
// 出力:object(stdClass)#2 (2) { ["name"]=> string(5) "Alice" ["age"]=> int(30) }
?>

ベストプラクティスのまとめ:

ユーザー入力、API レスポンス、データベースの結果など、外部データを処理する際はデータタイプが制御不能であることが多いため、型ジャグリングに頼らず型キャストを明示的に使用することを強く推奨します。これにより、コードの意図が明確になるだけでなく、発見しにくいバグの発生確率を大幅に下げることができます。