类型检测函数
概述
PHP 提供了一组 is_* 类型检测函数,用于判断变量的类型。这些函数返回布尔值,广泛应用于输入验证、条件分支和类型安全的代码中。与 PHP 7.0+ 的标量类型声明配合使用,可以在运行时进行灵活的类型检查。
PHP 版本说明
is_*系列函数大多自 PHP 4 起可用is_iterable自 PHP 7.1 引入is_countable自 PHP 7.3 引入get_debug_type()自 PHP 8.0 引入,返回更精确的类型名
基础概念
类型检测函数分类
| 类别 | 函数 | 说明 |
|---|---|---|
| 标量类型 | is_int, is_float, is_string, is_bool | 基本数据类型检查 |
| 复合类型 | is_array, is_object, is_callable, is_resource | 复合数据类型检查 |
| 特殊类型 | is_null, is_numeric, is_scalar | 特殊类型检查 |
| PHP 7+ | is_iterable, is_countable | 接口/特性检查 |
| 综合 | gettype, get_debug_type | 获取类型名称 |
语法与代码
标量类型检测
php
<?php
declare(strict_types=1);
// is_int / is_integer / is_long(三者完全相同)
var_dump(is_int(42)); // true
var_dump(is_int(-10)); // true
var_dump(is_int(3.14)); // false
var_dump(is_int('42')); // false
var_dump(is_int(PHP_INT_MAX)); // true
// is_float / is_double / is_real(三者完全相同)
var_dump(is_float(3.14)); // true
var_dump(is_float(1.0)); // true
var_dump(is_float(42)); // false
var_dump(is_float(INF)); // true
var_dump(is_float(NAN)); // true
// is_string
var_dump(is_string('hello')); // true
var_dump(is_string('')); // true
var_dump(is_string(42)); // false
var_dump(is_string('42')); // true(字符串 '42',不是整数)
var_dump(is_string('3.14')); // true
// is_bool
var_dump(is_bool(true)); // true
var_dump(is_bool(false)); // true
var_dump(is_bool(0)); // false
var_dump(is_bool('true')); // false
var_dump(is_bool(1)); // false复合类型检测
php
<?php
declare(strict_types=1);
// is_array
var_dump(is_array([1, 2, 3])); // true
var_dump(is_array(['key' => 'val'])); // true
var_dump(is_array([])); // true(空数组也是数组)
var_dump(is_array('hello')); // false
var_dump(is_array(new stdClass())); // false
// is_object
var_dump(is_object(new stdClass())); // true
var_dump(is_object((object)['a'=>1])); // true(PHP 8.0 匿名对象)
var_dump(is_object([1, 2])); // false
var_dump(is_object(null)); // false
// is_callable
var_dump(is_callable('strlen')); // true
var_dump(is_callable(fn() => true)); // true
var_dump(is_callable(['class', 'method'])); // 取决于方法是否存在
var_dump(is_callable('nonexistent')); // false
var_dump(is_callable(42)); // false
var_dump(is_callable(['ArrayObject', 'count'])); // true
// is_resource
$fp = fopen('php://memory', 'r');
var_dump(is_resource($fp)); // true
fclose($fp);
var_dump(is_resource($fp)); // false(已关闭的资源)特殊类型检测
php
<?php
declare(strict_types=1);
// is_null
var_dump(is_null(null)); // true
var_dump(is_null(0)); // false
var_dump(is_null('')); // false
var_dump(is_null(false)); // false
var_dump(is_null($undefined)); // true(未定义变量视为 null)
// is_numeric:检查是否为数字或数字字符串
var_dump(is_numeric(42)); // true
var_dump(is_numeric(3.14)); // true
var_dump(is_numeric('42')); // true
var_dump(is_numeric('3.14')); // true
var_dump(is_numeric('-100')); // true
var_dump(is_numeric('+1.5e2')); // true(科学计数法)
var_dump(is_numeric('0x1A')); // true(十六进制)
var_dump(is_numeric('hello')); // false
var_dump(is_numeric('42abc')); // false
var_dump(is_numeric('')); // false
// is_scalar:检查是否为标量类型(int, float, string, bool)
var_dump(is_scalar(42)); // true
var_dump(is_scalar(3.14)); // true
var_dump(is_scalar('hello')); // true
var_dump(is_scalar(true)); // true
var_dump(is_scalar(null)); // false
var_dump(is_scalar([1, 2])); // false
var_dump(is_scalar(new stdClass())); // falsePHP 7+ 新增类型检测
php
<?php
declare(strict_types=1);
// is_iterable(PHP 7.1+):检查是否为数组或 Traversable
var_dump(is_iterable([1, 2, 3])); // true(数组)
var_dump(is_iterable(new ArrayIterator())); // true(Traversable)
var_dump(is_iterable(new stdClass())); // false
var_dump(is_iterable('hello')); // false
var_dump(is_iterable(42)); // false
// is_countable(PHP 7.3+):检查是否可使用 count()
var_dump(is_countable([1, 2, 3])); // true
var_dump(is_countable(new ArrayIterator())); // true
var_dump(is_countable('hello')); // false
var_dump(is_countable(new stdClass())); // false(PHP 7.2 前为 true)gettype 与 get_debug_type
php
<?php
declare(strict_types=1);
// gettype:返回通用类型名(PHP 所有版本)
echo gettype(42) . "\n"; // integer
echo gettype(3.14) . "\n"; // double
echo gettype('hello') . "\n"; // string
echo gettype(true) . "\n"; // boolean
echo gettype(null) . "\n"; // NULL
echo gettype([1, 2]) . "\n"; // array
echo gettype(new stdClass()) . "\n"; // object
echo gettype(fn() => true) . "\n"; // object
// get_debug_type(PHP 8.0+):返回更精确的类型名
echo get_debug_type(42) . "\n"; // int
echo get_debug_type(3.14) . "\n"; // float
echo get_debug_type(true) . "\n"; // bool
echo get_debug_type(null) . "\n"; // null
echo get_debug_type([1, 2]) . "\n"; // array
echo get_debug_type(new stdClass()) . "\n"; // stdClass
echo get_debug_type(fn() => true) . "\n"; // Closure
echo get_debug_type(new ArrayIterator()) . "\n"; // ArrayIterator
echo get_debug_type(InvalidArgumentException::class) . "\n"; // stringget_debug_type 优势
get_debug_type() 返回的类型名更精确:int vs integer、float vs double、Closure vs object。推荐在 PHP 8.0+ 中优先使用。
详细说明
is_numeric vs is_int 的区别
php
<?php
declare(strict_types=1);
$input = '42';
var_dump(is_numeric($input)); // true('42' 是数字字符串)
var_dump(is_int($input)); // false('42' 是字符串,不是整数)
// 实际使用场景
function parseInt(string $input): ?int
{
if (!is_numeric($input)) {
return null;
}
return (int) $input;
}
echo parseInt('42') . "\n"; // 42
echo parseInt('3.14') . "\n"; // 3
var_dump(parseInt('abc')); // NULL类型检测与严格类型
php
<?php
declare(strict_types=1);
function processNumber(int $number): int
{
return $number * 2;
}
// 严格模式下,传入非 int 会抛出 TypeError
// processNumber('42'); // TypeError
// 运行时检查
function safeProcess(mixed $input): int
{
if (!is_int($input) && !is_numeric($input)) {
throw new InvalidArgumentException('Expected a number');
}
return (int) $input * 2;
}
echo safeProcess(42) . "\n"; // 84
echo safeProcess('42') . "\n"; // 84is_callable 的详细用法
php
<?php
declare(strict_types=1);
// 检查各种可调用结构
var_dump(is_callable('strlen')); // true(函数名)
var_dump(is_callable(fn() => true)); // true(闭包)
var_dump(is_callable([ArrayObject::class, 'count'])); // true(静态方法)
var_dump(is_callable([new ArrayObject(), 'count'])); // true(实例方法)
var_dump(is_callable('nonexistent_function')); // false
// is_callable 的第二个参数:获取可调用名称
$callableName = null;
var_dump(is_callable('strlen', false, $callableName)); // true
echo $callableName . "\n"; // strlen
// 仅检查语法(不检查函数是否存在)
var_dump(is_callable('someUnknownFunction', true)); // true(语法合法)
var_dump(is_callable('someUnknownFunction', false)); // false(函数不存在)实战示例
输入验证器
php
<?php
declare(strict_types=1);
class Validator
{
private array $rules = [];
private array $errors = [];
public function string(string $field): self
{
$this->rules[$field] = fn(mixed $v): bool => is_string($v);
return $this;
}
public function integer(string $field): self
{
$this->rules[$field] = fn(mixed $v): bool => is_int($v);
return $this;
}
public function numeric(string $field): self
{
$this->rules[$field] = fn(mixed $v): bool => is_numeric($v);
return $this;
}
public function email(string $field): self
{
$this->rules[$field] = fn(mixed $v): bool => is_string($v) && filter_var($v, FILTER_VALIDATE_EMAIL) !== false;
return $this;
}
public function validate(array $data): bool
{
$this->errors = [];
foreach ($this->rules as $field => $rule) {
$value = $data[$field] ?? null;
if (!$rule($value)) {
$type = get_debug_type($value);
$this->errors[$field] = "Field '{$field}' expected valid type, got {$type}";
}
}
return empty($this->errors);
}
public function getErrors(): array
{
return $this->errors;
}
}
$validator = (new Validator())
->string('name')
->integer('age')
->email('email');
$data = ['name' => 'Alice', 'age' => '30', 'email' => 'not-an-email'];
$isValid = $validator->validate($data);
if (!$isValid) {
print_r($validator->getErrors());
// Array ( [age] => Field 'age' expected valid type, got string [email] => ... )
}类型安全的数组处理
php
<?php
declare(strict_types=1);
function ensureIntArray(array $items): array
{
foreach ($items as $key => $item) {
if (!is_int($item)) {
throw new TypeError("Item at index {$key} must be int, " . get_debug_type($item) . " given");
}
}
return $items;
}
function ensureStringArray(array $items): array
{
return array_map(function (mixed $item, int $key): string {
if (!is_string($item) && !is_numeric($item)) {
throw new TypeError("Item at index {$key} must be string");
}
return (string) $item;
}, $items, array_keys($items));
}
// 使用示例
try {
$ints = ensureIntArray([1, 2, 3, 'four']); // TypeError
} catch (TypeError $e) {
echo $e->getMessage() . "\n";
}
$strings = ensureStringArray([1, 2, 'hello', 3.14]);
print_r($strings); // Array ( [0] => 1 [1] => 2 [2] => hello [3] => 3.14 )注意事项
常见陷阱
- is_numeric 包含十六进制和科学计数法
php
<?php
declare(strict_types=1);
var_dump(is_numeric('0xFF')); // true(十六进制)
var_dump(is_numeric('1e10')); // true(科学计数法)
var_dump(is_numeric('+42')); // true
var_dump(is_numeric('-3.14')); // true
// 如果只需要十进制数字
function isDecimalNumber(string $input): bool
{
return preg_match('/^-?\d+(\.\d+)?$/', $input) === 1;
}
var_dump(isDecimalNumber('42')); // true
var_dump(isDecimalNumber('0xFF')); // false
var_dump(isDecimalNumber('1e10')); // false- is_scalar 不包含 null
php
<?php
declare(strict_types=1);
var_dump(is_scalar(null)); // false
var_dump(is_scalar(42)); // true
var_dump(is_scalar('abc')); // true
var_dump(is_scalar(true)); // true
// null 不被视为标量- 对象类型需要 get_class
php
<?php
declare(strict_types=1);
$obj = new ArrayIterator();
// is_object 只知道它是对象,不知道具体类
var_dump(is_object($obj)); // true
// get_class 获取具体类名
echo get_class($obj) . "\n"; // ArrayIterator
// instanceof 检查继承关系
var_dump($obj instanceof ArrayIterator); // true
var_dump($obj instanceof Traversable); // true
var_dump($obj instanceof IteratorAggregate); // true最佳实践
1. 优先使用类型声明而非 is_* 检查
php
<?php
declare(strict_types=1);
// 推荐:使用类型声明
function process(int $value): int
{
return $value * 2;
}
// 不推荐:手动检查
function processManual(mixed $value): int
{
if (!is_int($value)) {
throw new TypeError('Expected int');
}
return $value * 2;
}2. 混合类型使用 match + get_debug_type
php
<?php
declare(strict_types=1);
function describeType(mixed $value): string
{
return match (true) {
is_int($value) => "integer ({$value})",
is_float($value) => "float ({$value})",
is_string($value) => "string (length: " . strlen($value) . ")",
is_bool($value) => "boolean (" . ($value ? 'true' : 'false') . ")",
is_array($value) => "array (" . count($value) . " items)",
is_object($value) => "object (" . get_class($value) . ")",
is_null($value) => "null",
is_resource($value) => "resource",
default => "unknown type (" . get_debug_type($value) . ")",
};
}
echo describeType(42) . "\n"; // integer (42)
echo describeType([1, 2, 3]) . "\n"; // array (3 items)3. 使用 PHP 8.0+ 的 get_debug_type
php
<?php
declare(strict_types=1);
// 旧方式(gettype 返回不一致的名称)
echo gettype(fn() => true) . "\n"; // object
// 新方式(PHP 8.0+)
echo get_debug_type(fn() => true) . "\n"; // Closure
// 旧方式
echo gettype(42) . "\n"; // integer
// 新方式
echo get_debug_type(42) . "\n"; // int