PHP对象必须通过class定义类再用new实例化,不能直接声明;类型声明User $u要求变量名合法且传入实例,否则报TypeError;调用前须确保对象非null,避免“Call to a member function on null”错误。

PHP对象类型不是“声明一个变量叫对象”,而是通过类定义 + 实例化来产生真实可用的对象,所有操作都围绕 class、new 和 -> 展开。
怎么创建一个能用的对象
对象必须从类来,没有类就没有对象。类是模板,对象是按模板造出来的具体实例。
- 用
class定义一个类,里面至少要有属性(如public $name)或方法(如public function say() { ... }) - 用
new ClassName()实例化,得到一个对象,比如$user = new User(); - 不能直接写
$obj = object;或$obj = (object)[];就当它是业务对象——它只是stdClass实例,没行为、没约束、不适用于业务逻辑层
为什么传参时写 User $u 会报错
这是最常见的卡点:类型声明不是语法糖,它强制要求变量名存在且合法。
- 错误写法:
function handle(User): void→ 缺少参数变量名,PHP 直接 Parse error - 正确写法:
function handle(User $u): void→$u是你在函数体内唯一能访问该对象的入口 - 如果传入非
User实例(比如数组、字符串、null),PHP 在运行时抛出TypeError(启用严格模式后更早报错) - 子类实例可以传入,比如
Admin extends User,handle(new Admin())合法
-> 调用时总提示“Call to a member function on null”
这不是对象类型问题,而是你没确保 $obj 真的是个有效对象。
立即学习“PHP免费学习笔记(深入)”;
- 常见原因:构造失败、依赖未注入、数据库查不到数据导致
$user = null,但你还写了$user->getName() - 安全做法:调用前加判断,
if ($user instanceof User) { $user->getName(); },或用空合并$user?->getName()(PHP 8.0+) - 别依赖
isset($user)——isset(null)是 false,但isset($user)对未定义变量才有效;对已定义为null的变量,要用$user !== null或is_object($user)
什么时候该用 (object)[] 或 new stdClass
它们只适合临时容器、配置透传、JSON 中间态,不适合建模业务实体。
-
$data = (object)['id' => 1, 'name' => 'foo'];可以快速转成带属性的对象,但无法加方法、无法类型约束、IDE 不识别结构 -
json_decode($json, false)默认返回stdClass实例,如果你后续要频繁调用->,又不想定义完整类,它勉强够用 - 一旦逻辑变复杂(比如要验证、要序列化、要和 Doctrine/Laravel ORM 交互),立刻换成真实类,否则后期补类型声明、加方法、改构造逻辑的成本远高于一开始写清楚
最易被忽略的一点:对象类型声明本身不解决空值问题,也不自动初始化依赖;它只划清“谁可以进来”的边界。真正的健壮性,靠的是构造函数把必要依赖收全、用类型声明锁死输入、再配合明确的空值检查策略。



















