[PHP]settype完全解説|変数の型を動的に変換する方法とキャストとの違いを徹底比較

PHP

はじめに

PHPは動的型付け言語であり、変数の型は実行時に自動で変換されることが多いですが、明示的に型を変換したい場面は少なくありません。そのための手段として、PHPには大きく2つのアプローチがあります。

  • キャスト演算子(int)$val(string)$val のように新しい値を返す
  • settype():変数そのものの型を破壊的に変換する

settype() は変数を参照渡しで受け取り、変数自体の型と値を直接書き換える関数です。戻り値は成功/失敗を示す bool であり、変換後の値は引数の変数に反映されます。

本記事では、この独特な挙動を持つ settype() の仕様・変換規則・実践的なユースケースを詳しく解説します。


関数の基本情報

項目内容
関数名settype()
利用可能バージョンPHP 4以降
所属変数操作関数(Variable Handling)
戻り値bool(成功時true、失敗時false
拡張機能不要(コア関数)

シグネチャ

settype(mixed &$var, string $type): bool

パラメータ

パラメータ説明
$varmixed&型を変換する変数(参照渡し
$typestring変換後の型名(下表参照)

指定できる型名

$type 文字列変換後の型
"bool" / "boolean"bool
"int" / "integer"int
"float" / "double"float
"string"string
"array"array
"object"objectstdClass
"null"null

上記以外の文字列を渡すと false を返します。


キャスト演算子との決定的な違い

$a = "42";
$b = "42";

// キャスト:元の変数は変わらず、新しい値を返す
$intVal = (int)$a;
var_dump($a);       // string(2) "42" ← 変わっていない
var_dump($intVal);  // int(42)

// settype:変数そのものが書き換わる
settype($b, 'int');
var_dump($b);       // int(42) ← 変数自体が変わった

使い分けの指針

観点キャスト (int)$vsettype($v, 'int')
変数への影響元の変数は不変元の変数を破壊的に変換
戻り値変換後の成功/失敗の bool
可読性高い(一目で型がわかる)やや低い
動的な型指定❌ 型を文字列で渡せない✅ 型名を変数で渡せる
主な用途一般的な型変換動的・ループでの一括変換

型変換の動作一覧

→ int への変換

元の値変換後備考
true1
false0
"42"42
"3.9"3切り捨て
"12abc"12先頭の数値部分のみ
"abc"0数値でない場合は0
null0
3.93切り捨て

→ float への変換

元の値変換後
"3.14"3.14
"1e3"1000.0
true1.0
null0.0

→ bool への変換

Falsy(falseになる値)Truthy(trueになる値)
00.0"0"""[]nullそれ以外すべて

→ string への変換

元の値変換後
true"1"
false""
null""
42"42"
3.14"3.14"

→ array への変換

元の値変換後
スカラー値 $v[$v](要素1つの配列)
null[](空配列)
オブジェクトプロパティ名をキーにした配列

→ object への変換

元の値変換後
連想配列 ['k'=>'v'](object)['k'=>'v'](stdClass)
スカラー値scalarプロパティを持つstdClass
null空のstdClass

実践サンプル集(PHP 8.x対応)

サンプル1:基本的な型変換の動作確認

<?php
declare(strict_types=1);

$cases = [
    ['42',     'int'],
    ['3.14',   'float'],
    [0,        'bool'],
    [1,        'bool'],
    ['hello',  'int'],
    ['12abc',  'int'],
    [null,     'string'],
    [true,     'string'],
    [false,    'string'],
    ['99.9',   'int'],
];

echo str_pad('元の値', 14) . str_pad('型', 8) . "変換後\n";
echo str_repeat('-', 45) . "\n";

foreach ($cases as [$value, $type]) {
    $before = var_export($value, true);
    $var = $value;
    settype($var, $type);
    $after = var_export($var, true);
    printf("%-14s %-8s %s\n", $before, "→ {$type}", $after);
}

実行結果:

元の値          型        変換後
---------------------------------------------
'42'           → int    42
'3.14'         → float  3.14
0              → bool   false
1              → bool   true
'hello'        → int    0
'12abc'        → int    12
NULL           → string ''
true           → string '1'
false          → string ''
'99.9'         → int    99

解説: '12abc'int12になる(先頭の数値部分を採用)、'hello'int0になるなど、PHPの型ジャグリングの挙動がsettype()でも同様に適用されます。


サンプル2:動的な型名を使った一括バリデーション・変換

型名を動的に文字列で渡せるsettype()の最大の強みを活かしたパターンです。

<?php
declare(strict_types=1);

/**
 * フォーム入力値を定義したスキーマに従って型変換するクラス
 */
class FormTypeCaster
{
    /**
     * @param array<string, string> $schema フィールド名 => 期待する型
     */
    public function __construct(
        private readonly array $schema
    ) {}

    /**
     * @param  array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function cast(array $input): array
    {
        $result = [];

        foreach ($this->schema as $field => $type) {
            if (!array_key_exists($field, $input)) {
                continue;
            }

            $value = $input[$field];
            if (!settype($value, $type)) {
                throw new \InvalidArgumentException(
                    "'{$type}' は有効な型ではありません(フィールド: {$field})"
                );
            }
            $result[$field] = $value;
        }

        return $result;
    }
}

// 使用例:フォーム送信データ(すべて文字列として届く)
$rawInput = [
    'user_id'   => '42',
    'age'       => '25',
    'price'     => '1980.5',
    'is_active' => '1',
    'name'      => 'Alice',
    'score'     => '87.3',
];

$schema = [
    'user_id'   => 'int',
    'age'       => 'int',
    'price'     => 'float',
    'is_active' => 'bool',
    'name'      => 'string',
    'score'     => 'float',
];

$caster = new FormTypeCaster($schema);
$casted = $caster->cast($rawInput);

foreach ($casted as $key => $value) {
    printf("%-12s : %-8s = %s\n", $key, gettype($value), var_export($value, true));
}

実行結果:

user_id      : integer  = 42
age          : integer  = 25
price        : double   = 1980.5
is_active    : boolean  = true
name         : string   = 'Alice'
score        : double   = 87.3

解説: settype() は型名を文字列変数で渡せるため、スキーマ配列との組み合わせが非常に相性がよいです。キャスト演算子では switchmatch が必要になる場面を簡潔に実装できます。


サンプル3:配列の全要素を一括型変換

配列内の値を一括で同じ型に変換するユースケースです。

<?php
declare(strict_types=1);

/**
 * 配列の全要素を指定した型に変換する
 *
 * @template T
 * @param  array<mixed>  $items
 * @param  string        $type
 * @return array<mixed>
 */
function castAll(array &$items, string $type): bool
{
    foreach ($items as &$item) {
        if (!settype($item, $type)) {
            return false;
        }
    }
    unset($item);
    return true;
}

// CSVから読み込んだ数値データ(すべて文字列)
$csvRow     = ['10', '25', '3', '99', '42', '7'];
$scoreStrs  = ['85.5', '92.0', '78.3', '66.7', '95.1'];
$flagStrs   = ['1', '0', '1', '1', '0'];

castAll($csvRow, 'int');
castAll($scoreStrs, 'float');
castAll($flagStrs, 'bool');

echo "整数配列: ";
echo implode(', ', array_map(fn($v) => "$v", $csvRow)) . "\n";
// 10, 25, 3, 99, 42, 7

echo "合計: " . array_sum($csvRow) . "\n"; // 186

echo "\nスコア配列: ";
echo implode(', ', $scoreStrs) . "\n";
// 85.5, 92, 78.3, 66.7, 95.1

echo "平均: " . round(array_sum($scoreStrs) / count($scoreStrs), 2) . "\n"; // 83.52

echo "\nフラグ配列: ";
echo implode(', ', array_map(fn($v) => $v ? 'true' : 'false', $flagStrs)) . "\n";
// true, false, true, true, false

実行結果:

整数配列: 10, 25, 3, 99, 42, 7
合計: 186

スコア配列: 85.5, 92, 78.3, 66.7, 95.1
平均: 83.52

フラグ配列: true, false, true, true, false

解説: foreach で参照渡し(&$item)と settype() を組み合わせることで、配列全体を一括変換できます。array_map() でキャストするより変数を直接書き換えるスタイルになります。


サンプル4:設定値の型安全な読み込み

設定ファイルやデータベースから取得した値を確実に正しい型で扱うパターンです。

<?php
declare(strict_types=1);

class TypedConfig
{
    private array $store = [];

    /** @param array<string, array{value: mixed, type: string}> $definitions */
    public function __construct(array $definitions)
    {
        foreach ($definitions as $key => $def) {
            $value = $def['value'];
            settype($value, $def['type']);
            $this->store[$key] = $value;
        }
    }

    public function get(string $key, mixed $default = null): mixed
    {
        return $this->store[$key] ?? $default;
    }

    public function getInt(string $key, int $default = 0): int
    {
        $v = $this->store[$key] ?? $default;
        return is_int($v) ? $v : (int)$v;
    }

    public function getBool(string $key, bool $default = false): bool
    {
        $v = $this->store[$key] ?? $default;
        return is_bool($v) ? $v : (bool)$v;
    }

    public function getString(string $key, string $default = ''): string
    {
        $v = $this->store[$key] ?? $default;
        return is_string($v) ? $v : (string)$v;
    }
}

// .envやDBから取得した「すべて文字列」の設定値
$rawConfig = [
    'db_port'      => ['value' => '3306',  'type' => 'int'],
    'debug_mode'   => ['value' => '1',     'type' => 'bool'],
    'max_retries'  => ['value' => '3',     'type' => 'int'],
    'timeout'      => ['value' => '30.5',  'type' => 'float'],
    'app_name'     => ['value' => 'MyApp', 'type' => 'string'],
    'cache_enable' => ['value' => '0',     'type' => 'bool'],
];

$config = new TypedConfig($rawConfig);

echo "db_port      : " . $config->getInt('db_port') . " (" . gettype($config->get('db_port')) . ")\n";
echo "debug_mode   : " . ($config->getBool('debug_mode') ? 'true' : 'false') . "\n";
echo "timeout      : " . $config->get('timeout') . " (" . gettype($config->get('timeout')) . ")\n";
echo "cache_enable : " . ($config->getBool('cache_enable') ? 'true' : 'false') . "\n";
echo "app_name     : " . $config->getString('app_name') . "\n";

実行結果:

db_port      : 3306 (integer)
debug_mode   : true
timeout      : 30.5 (double)
cache_enable : false
app_name     : MyApp

解説: 型定義をデータ構造として保持し、settype() でコンストラクタ内に一括変換するパターンです。設定値の型保証を宣言的に記述できます。


サンプル5:オブジェクト・配列変換の動作

arrayobject への変換という少し特殊なケースです。

<?php
declare(strict_types=1);

// --- array への変換 ---

// スカラー → 配列
$val = 42;
settype($val, 'array');
var_dump($val); // array(1) { [0]=> int(42) }

// null → 空配列
$val = null;
settype($val, 'array');
var_dump($val); // array(0) {}

// オブジェクト → 配列(プロパティがキーになる)
$obj = new stdClass();
$obj->name  = 'Alice';
$obj->score = 95;
settype($obj, 'array');
print_r($obj);
// Array ( [name] => Alice [score] => 95 )

// --- object への変換 ---

// 連想配列 → stdClass
$assoc = ['id' => 1, 'name' => 'Bob', 'active' => true];
settype($assoc, 'object');
var_dump($assoc instanceof stdClass); // bool(true)
echo $assoc->name . "\n";           // Bob

// スカラー → scalar プロパティを持つ stdClass
$num = 100;
settype($num, 'object');
var_dump($num);
// object(stdClass)#1 (1) { ["scalar"]=> int(100) }

// --- null への変換 ---
$data = ['lots', 'of', 'data'];
settype($data, 'null');
var_dump($data); // NULL

実行結果:

array(1) {
  [0]=>
  int(42)
}
array(0) {
}
Array
(
    [name] => Alice
    [score] => 95
)
bool(true)
Bob
object(stdClass)#1 (1) {
  ["scalar"]=>
  int(100)
}
NULL

解説: objectへの変換ではstdClassが生成されます。連想配列のキーがそのままプロパティ名になります。nullへの変換は変数をリセットする用途に使えます。


サンプル6:settype()の戻り値を使ったバリデーション付き変換

変換の成否を確認しながら処理するパターンです。

<?php
declare(strict_types=1);

/**
 * 型変換の結果を表すValue Object
 */
class CastResult
{
    private function __construct(
        public readonly bool $success,
        public readonly mixed $value,
        public readonly string $errorMessage = '',
    ) {}

    public static function ok(mixed $value): self
    {
        return new self(true, $value);
    }

    public static function fail(string $message): self
    {
        return new self(false, null, $message);
    }
}

/**
 * 安全な型変換(変換後の値が意図通りか検証付き)
 */
function safeCast(mixed $value, string $type): CastResult
{
    $validTypes = ['bool','boolean','int','integer','float','double','string','array','object','null'];

    if (!in_array($type, $validTypes, true)) {
        return CastResult::fail("不明な型: {$type}");
    }

    $var = $value;
    if (!settype($var, $type)) {
        return CastResult::fail("変換失敗: " . var_export($value, true) . " → {$type}");
    }

    // 追加検証:数値変換で情報が失われすぎていないか
    if (in_array($type, ['int', 'integer'], true)
        && is_string($value)
        && !is_numeric($value)
        && $value !== ''
    ) {
        return CastResult::fail(
            "非数値文字列を int に変換: '{$value}' → {$var}(情報損失の可能性)"
        );
    }

    return CastResult::ok($var);
}

// --- テスト ---
$tests = [
    ['42',      'int'],
    ['3.14',    'float'],
    ['hello',   'int'],    // 非数値 → 警告
    ['1',       'bool'],
    ['invalid', 'xyz'],    // 不正な型
    [null,      'string'],
    [[1,2,3],   'object'],
];

foreach ($tests as [$value, $type]) {
    $result = safeCast($value, $type);
    $label  = $result->success ? '✅' : '❌';
    $detail = $result->success
        ? var_export($result->value, true) . ' (' . gettype($result->value) . ')'
        : $result->errorMessage;
    printf(
        "%s %-12s → %-8s %s\n",
        $label,
        var_export($value, true),
        $type,
        $detail
    );
}

実行結果:

✅ '42'         → int     42 (integer)
✅ '3.14'       → float   3.14 (double)
❌ 'hello'      → int     非数値文字列を int に変換: 'hello' → 0(情報損失の可能性)
✅ '1'          → bool    true (boolean)
❌ 'invalid'    → xyz     不明な型: xyz
✅ NULL         → string  '' (string)
✅ array (...)  → object  object(stdClass)#1 ... (object)

解説: settype() 自体は不正な型名以外ではほぼ true を返すため、変換後の値が意図通りかを独自に検証するラッパーが実用上有効です。データ品質が重要な場面ではこのパターンが役立ちます。


よくある落とし穴

① 戻り値で変換結果を得ようとする

// ❌ settype() はboolを返す(変換後の値ではない)
$result = settype($var, 'int'); // true/false

// ✅ 変換後の値は $var 自体に入っている
settype($var, 'int');
echo $var; // 変換後の値

② false → string の挙動に注意

$val = false;
settype($val, 'string');
var_dump($val); // string(0) "" ← "false"にはならない!

false を文字列に変換すると "" (空文字)になります。"false" という文字列にはなりません。

③ "1" → bool は true

$val = "0";
settype($val, 'bool');
var_dump($val); // bool(false)

$val = "false"; // ← "false"という文字列
settype($val, 'bool');
var_dump($val); // bool(true) ← !"false"は空でない文字列なのでtrue

"false" という文字列は true に変換されます(空文字でも"0"でもないため)。

④ 元の変数が破壊される

$original = "42.5";
settype($original, 'int');
// $original はもう "42.5" ではなく 42 になっている
// 元の値が必要な場合はコピーしてから変換する

$copy = $original;
settype($copy, 'int');

⑤ PHP 8.x での strict_types との関係

declare(strict_types=1) は関数の引数型の厳格化であり、settype() の動作には影響しません。settype() は常に「弱い型変換」を行います。


まとめ

ポイント内容
主な用途動的な型変換・スキーマ駆動の一括変換・配列要素の型統一
キャストとの違い変数を破壊的に変換する(元の変数が書き換わる)
最大の強み型名を文字列変数で渡せる(動的型指定)
戻り値変換後の値ではなく成功/失敗のbool
注意点false"""false"trueなど直感に反する変換がある
PHP 8.x推奨通常はキャスト演算子やintval()等が推奨。settype()は動的な型名が必要な場面に

settype() はキャスト演算子と違い「型名を動的に渡せる」という唯一の強みがあります。スキーマ配列との組み合わせや大量データの一括型変換など、型名をデータとして扱いたい場面では今も有効な選択肢です。


PHP 8.x / 執筆時点の最新安定版にて動作確認済み

タイトルとURLをコピーしました