PHP 型別轉換 (Type Casting)

PHP 是弱型別語言,會自動進行型別轉換。你也可以手動強制轉換型別。

自動型別轉換

PHP 會根據運算的情境自動轉換型別:

<?php
// 字串轉數字
$sum = "10" + 5;
echo $sum;  // 15 (integer)
echo gettype($sum);  // integer

// 數字轉字串
$str = "The answer is " . 42;
echo $str;  // The answer is 42

// 布林轉換
if ("hello") {
    echo "非空字串視為 true";
}

// 比較時的轉換
var_dump("10" == 10);   // bool(true) - 字串轉為數字比較
var_dump("10" === 10);  // bool(false) - 嚴格比較不轉換
?>

字串轉數字的規則

<?php
// 以數字開頭的字串
echo "123abc" + 0;     // 123
echo "3.14hello" + 0;  // 3.14

// 不是以數字開頭
echo "hello" + 0;      // 0 (PHP 8 會產生警告)

// 科學記號
echo "1e2" + 0;        // 100

// 空白會被忽略
echo "  123  " + 0;    // 123
?>
PHP 8 開始,對非數字字串進行數學運算會產生警告或錯誤,建議明確進行型別轉換。

強制型別轉換

使用 (type) 語法進行強制轉換:

轉換語法
整數(int)(integer)
浮點數(float)(double)(real)
字串(string)
布林(bool)(boolean)
陣列(array)
物件(object)
unset(unset) (已棄用)

轉換為整數 (int)

<?php
// 浮點數 → 整數(無條件捨去)
echo (int) 3.7;     // 3
echo (int) -3.7;    // -3

// 字串 → 整數
echo (int) "42";      // 42
echo (int) "42.9";    // 42
echo (int) "42abc";   // 42
echo (int) "abc42";   // 0
echo (int) "abc";     // 0

// 布林 → 整數
echo (int) true;    // 1
echo (int) false;   // 0

// null → 整數
echo (int) null;    // 0

// 陣列 → 整數
echo (int) [];        // 0
echo (int) [1, 2, 3]; // 1 (非空陣列)
?>

轉換為浮點數 (float)

<?php
// 整數 → 浮點數
echo (float) 42;      // 42.0

// 字串 → 浮點數
echo (float) "3.14";    // 3.14
echo (float) "3.14abc"; // 3.14
echo (float) "abc";     // 0

// 布林 → 浮點數
echo (float) true;    // 1.0
echo (float) false;   // 0.0
?>

轉換為字串 (string)

<?php
// 整數 → 字串
echo (string) 42;     // "42"

// 浮點數 → 字串
echo (string) 3.14;   // "3.14"
echo (string) 1e2;    // "100"

// 布林 → 字串
echo (string) true;   // "1"
echo (string) false;  // "" (空字串)

// null → 字串
echo (string) null;   // "" (空字串)

// 陣列 → 字串
echo (string) [1, 2]; // "Array" (會產生警告)

// 物件 → 字串 (需要 __toString 方法)
class User {
    public function __toString(): string {
        return "User Object";
    }
}
echo (string) new User();  // "User Object"
?>

轉換為布林 (bool)

以下值轉換為 false

<?php
// 這些值都是 false
var_dump((bool) false);      // false
var_dump((bool) 0);          // false
var_dump((bool) 0.0);        // false
var_dump((bool) -0.0);       // false
var_dump((bool) "");         // false
var_dump((bool) "0");        // false
var_dump((bool) []);         // false
var_dump((bool) null);       // false

// 其他值都是 true
var_dump((bool) 1);          // true
var_dump((bool) -1);         // true
var_dump((bool) "hello");    // true
var_dump((bool) "false");    // true (非空字串)
var_dump((bool) [0]);        // true (非空陣列)
var_dump((bool) new stdClass()); // true
?>

轉換為陣列 (array)

<?php
// 純量 → 陣列
$arr = (array) "hello";
print_r($arr);  // Array ( [0] => hello )

$arr = (array) 42;
print_r($arr);  // Array ( [0] => 42 )

// null → 陣列
$arr = (array) null;
print_r($arr);  // Array ( )

// 物件 → 陣列(屬性變成鍵值)
class Person {
    public $name = "Alice";
    public $age = 25;
}
$arr = (array) new Person();
print_r($arr);
// Array ( [name] => Alice [age] => 25 )
?>

轉換為物件 (object)

<?php
// 陣列 → 物件
$arr = ["name" => "Alice", "age" => 25];
$obj = (object) $arr;
echo $obj->name;  // Alice
echo $obj->age;   // 25

// 純量 → 物件
$obj = (object) "hello";
echo $obj->scalar;  // hello

// null → 物件
$obj = (object) null;
print_r($obj);  // stdClass Object ( )
?>

使用函數轉換

intval(), floatval(), strval(), boolval()

<?php
// intval()
echo intval("42.9");    // 42
echo intval("42", 8);   // 34 (八進位轉換)
echo intval("ff", 16);  // 255 (十六進位轉換)

// floatval() 或 doubleval()
echo floatval("3.14abc");  // 3.14

// strval()
echo strval(42);        // "42"
echo strval(3.14);      // "3.14"
echo strval(true);      // "1"

// boolval()
var_dump(boolval(1));       // bool(true)
var_dump(boolval(""));      // bool(false)
var_dump(boolval("hello")); // bool(true)
?>

settype()

settype() 會直接修改變數的型別:

<?php
$var = "42";
echo gettype($var);  // string

settype($var, "integer");
echo gettype($var);  // integer
echo $var;           // 42

// 支援的型別
settype($var, "int");      // 或 "integer"
settype($var, "float");    // 或 "double"
settype($var, "string");
settype($var, "bool");     // 或 "boolean"
settype($var, "array");
settype($var, "object");
settype($var, "null");
?>

型別檢查函數

<?php
$int = 42;
$float = 3.14;
$string = "hello";
$bool = true;
$array = [1, 2, 3];
$null = null;

// is_* 系列函數
var_dump(is_int($int));         // bool(true)
var_dump(is_integer($int));     // bool(true) - 別名
var_dump(is_float($float));     // bool(true)
var_dump(is_double($float));    // bool(true) - 別名
var_dump(is_string($string));   // bool(true)
var_dump(is_bool($bool));       // bool(true)
var_dump(is_array($array));     // bool(true)
var_dump(is_null($null));       // bool(true)
var_dump(is_object(new stdClass())); // bool(true)

// is_numeric() - 檢查是否為數字或數字字串
var_dump(is_numeric(42));       // bool(true)
var_dump(is_numeric("42"));     // bool(true)
var_dump(is_numeric("42.5"));   // bool(true)
var_dump(is_numeric("3.14e2")); // bool(true)
var_dump(is_numeric("42abc"));  // bool(false)

// is_scalar() - 檢查是否為純量
var_dump(is_scalar(42));        // bool(true)
var_dump(is_scalar("hello"));   // bool(true)
var_dump(is_scalar([1, 2]));    // bool(false)

// is_callable() - 檢查是否可呼叫
var_dump(is_callable('strlen')); // bool(true)
var_dump(is_callable(fn() => 1)); // bool(true)
?>

型別判斷與取得

<?php
// gettype() - 取得型別名稱
echo gettype(42);       // integer
echo gettype(3.14);     // double (注意:是 double 不是 float)
echo gettype("hello");  // string
echo gettype(true);     // boolean
echo gettype([]);       // array
echo gettype(null);     // NULL

// get_debug_type() - PHP 8+ 取得更精確的型別名稱
echo get_debug_type(42);        // int
echo get_debug_type(3.14);      // float
echo get_debug_type("hello");   // string
echo get_debug_type(true);      // bool
echo get_debug_type([]);        // array
echo get_debug_type(null);      // null
echo get_debug_type(new stdClass()); // stdClass
?>

實際應用範例

處理表單輸入

<?php
// 表單輸入都是字串,需要轉換
$age = isset($_POST['age']) ? (int) $_POST['age'] : 0;
$price = isset($_POST['price']) ? (float) $_POST['price'] : 0.0;
$active = isset($_POST['active']) ? (bool) $_POST['active'] : false;
?>

安全的資料處理

<?php
function calculateDiscount($price, $discountPercent) {
    // 確保參數是正確的型別
    $price = (float) $price;
    $discountPercent = (float) $discountPercent;
    
    if ($discountPercent < 0 || $discountPercent > 100) {
        throw new InvalidArgumentException("折扣百分比必須在 0-100 之間");
    }
    
    return $price * (1 - $discountPercent / 100);
}

echo calculateDiscount("100", "20");  // 80
?>

JSON 資料處理

<?php
$json = '{"count": "42", "price": "99.99", "active": "1"}';
$data = json_decode($json, true);

// JSON 解析後的值可能是字串
$count = (int) $data['count'];
$price = (float) $data['price'];
$active = (bool) $data['active'];
?>