PHP 类型系统与严格模式
PHP 的类型系统经历过重大演变,从动态类型逐渐增加了静态类型特性,严格模式是这一演进中的关键特性。

类型系统基础
弱类型(默认模式)
// PHP 默认是弱类型,会自动进行类型转换
function add($a, $b) {
return $a + $b;
}
echo add("5", 3); // 8 - 字符串自动转为整数
echo add("5 apples", 3); // 8 - "5 apples" 转为 5
echo add("hello", 3); // 3 - "hello" 转为 0
类型声明(PHP 7+)
// 参数类型声明
function calculate(int $a, float $b): float {
return $a * $b;
}
// 默认模式下仍会尝试类型转换
echo calculate("5", 2.5); // 12.5 - "5" 转为整数 5
严格模式
启用严格模式
<?php
declare(strict_types=1);
// 现在类型必须严格匹配
function add(int $a, int $b): int {
return $a + $b;
}
// add("5", 3); // TypeError: 参数 1 必须是整数,字符串给定
add(5, 3); // 8 - 正确
严格模式的特性
- 作用域:基于文件级别,每个文件需要单独声明
- 继承影响:子类方法必须与父类保持相同的严格性
- 类型检查:不会进行隐式类型转换
支持的类型声明
declare(strict_types=1);
// 基本类型
function basicTypes(
int $int,
float $float,
string $string,
bool $bool,
array $array,
callable $callable
): void {}
// 特殊类型
function specialTypes(
mixed $mixed, // PHP 8.0+ - 任意类型
never $never, // PHP 8.1+ - 永不返回
void $void, // 无返回值
null $null, // 仅允许 null
false $false, // PHP 8.0+ - 仅允许 false
true $true, // PHP 8.2+ - 仅允许 true
): void {}
// 对象类型
function objectTypes(
stdClass $object, // 特定类名
object $objectType, // PHP 7.2+ - 任何对象
iterable $iterable, // PHP 7.1+ - 数组或 Traversable
): void {}
联合类型与交叉类型
declare(strict_types=1);
// 联合类型 (PHP 8.0+)
function processInput(int|string|array $input): void {
if (is_int($input)) {
echo "整数: $input";
} elseif (is_string($input)) {
echo "字符串: $input";
} else {
echo "数组";
}
}
// 可空联合类型
function findUser(int|null $id): ?string {
if ($id === null) {
return null;
}
return "User #$id";
}
// 交叉类型 (PHP 8.1+)
interface Loggable {
public function log(): void;
}
interface Serializable {
public function serialize(): string;
}
function processLoggableSerializable(Loggable&Serializable $item): void {
$item->log();
echo $item->serialize();
}
伪类型与内置类型
declare(strict_types=1);
// mixed - PHP 8.0+
function mixedExample(mixed $data): mixed {
return match(true) {
is_string($data) => strtoupper($data),
is_int($data) => $data * 2,
default => null
};
}
// never - 永远不会返回值
function throwException(string $message): never {
throw new \RuntimeException($message);
}
// void
function logMessage(string $message): void {
echo "[LOG] $message" . PHP_EOL;
// 不能有 return 语句(除非 return; 没有值)
}
类型推断与类型系统特性
declare(strict_types=1);
// 属性类型声明 (PHP 7.4+)
class User {
public string $name;
protected int $age;
private array $roles;
public ?DateTimeImmutable $createdAt = null;
// 只读属性 (PHP 8.1+)
public readonly string $email;
public function __construct(
string $name,
int $age,
string $email
) {
$this->name = $name;
$this->age = $age;
$this->email = $email;
}
}
// 返回类型推断
class Calculator {
public function add(int $a, int $b): static { // PHP 8.0+
$result = new static();
$result->value = $a + $b;
return $result;
}
private int $value = 0;
}
// 泛型风格 (通过 PHPDoc)
/** @template T */
class Collection {
/** @var array<int, T> */
private array $items = [];
/** @param T $item */
public function add(mixed $item): void {
$this->items[] = $item;
}
/** @return T */
public function get(int $index): mixed {
return $this->items[$index] ?? null;
}
}
// 使用方式
$users = new Collection();
$users->add(new User('Alice', 30, 'alice@example.com'));
$user = $users->get(0); // User|null
类型转换与注意事项
declare(strict_types=1);
// 安全的类型转换
function safeConversion(): void {
// 显式转换
$intValue = (int) "123"; // 123
$floatValue = (float) "3.14"; // 3.14
$stringValue = (string) 123; // "123"
$boolValue = (bool) 1; // true
// 类型转换函数
$intval = intval("456"); // 456
$floatval = floatval("7.89"); // 7.89
$strval = strval(true); // "1"
}
// 严格模式下的常见陷阱
function strictTraps(): void {
// 1. 除法总是返回 float 或 int
$result = 10 / 3; // 3.3333333333333 (float)
$result = 10 / 5; // 2.0 (float)
$result = intdiv(10, 3); // 3 (整数除法)
// 2. 字符串连接
$message = "Count: " . 5; // 总是字符串
}
// 类型判断
function typeChecking(mixed $value): string {
return match(true) {
is_int($value) => 'integer',
is_float($value) => 'float',
is_string($value) => 'string',
is_bool($value) => 'boolean',
is_array($value) => 'array',
is_object($value) => 'object: ' . get_class($value),
is_null($value) => 'null',
is_resource($value) => 'resource',
default => 'unknown'
};
}
最佳实践
declare(strict_types=1);
// 1. 始终使用严格模式
<?php
declare(strict_types=1);
// 你的代码...
// 2. 为所有函数和方法的参数和返回值添加类型声明
function createUser(string $name, string $email, int $age): User {
// 实现
}
// 3. 使用 nullable 类型表示可能为 null 的值
function findById(int $id): ?User {
// 实现
}
// 4. 使用联合类型增加灵活性
function formatValue(int|float|string $value): string {
// 实现
}
// 5. 使用 readonly 属性确保不变性
class Config {
public readonly array $settings;
public function __construct(array $settings) {
$this->settings = $settings;
}
}
// 6. 使用 value object 替代原始类型
class Email {
public readonly string $value;
public function __construct(string $email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Invalid email");
}
$this->value = $email;
}
}
性能考虑
严格模式下的类型检查会带来轻微的性能开销,但通常可以忽略不计,实际收益包括:
- 更早的错误发现:在开发阶段就能发现问题
- 更好的 IDE 支持:代码补全和类型提示更准确
- 自文档化:类型声明本身就是文档
- 更可靠的代码:减少类型相关的 bug
PHP 的类型系统已经从弱类型演变为具有丰富类型特性的语言,严格模式是 PHP 现代开发中的最佳实践,能显著提高代码质量和可维护性,建议在新项目中始终启用严格模式,并充分利用 PHP 提供的类型系统特性。