
本教程深入探讨php和laravel开发中常见的“trying to get property 'x' of non-object”错误。文章将分析该错误发生的根本原因,包括变量为空、非对象类型以及构造函数中属性初始化不当等问题。通过实际代码示例,我们将学习如何有效调试、验证数据类型,并遵循最佳实践来确保对象正确传递和属性正确赋值,从而避免此类运行时错误。
当你在PHP中尝试像访问对象属性一样去访问一个非对象类型(如 null、数组或标量)的变量时,就会抛出“Trying to get property 'X' of non-object”错误。这里的 X 代表你试图访问的属性名。
这个错误的核心在于,PHP运行时发现你左侧的变量(例如 $variable 在 $variable->property 中)并不是一个有效的对象实例,因此无法从中获取任何属性。
导致此错误的原因通常有以下几种情况:
这是最直接导致该错误的原因。当一个变量被期望是一个对象,但实际上它却是 null、一个数组、一个字符串或其他标量类型时,尝试通过 -> 运算符访问其属性就会报错。
立即学习“PHP免费学习笔记(深入)”;
场景描述:
示例代码 (Controller层):
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
// ... 其他use声明
// 假设这是你的控制器方法
public function sendDailyReports()
{
$emailRecipients = DB::select("
select
e.ID empID,
e.lname lname,
e.fname fname,
e.email email,
e.teamID,
e.agencyID,
e.accessProfileID,
e.accessTeams,
c.ID coID,
c.dDesc companyName,
c.product,
c.modules
from
emailrecipient_tb er
left join employee_tb e on er.empID = e.ID
left join company_tb c on er.coID = c.ID
where
er.isDAR = 1 and
er.isActive = 1 and
c.isActive = 1
");
foreach ($emailRecipients as $rowRecipient) {
// 在这里,如果 $rowRecipient 意外地是 null 或非对象,
// 那么在 Mail::to($rowRecipient->email) 之前,
// 或者在 DailyActivityReport2 构造函数内部访问 $rowRecipient->coID 时就会报错。
// **排查点:**
// 1. 在这里使用 dd($rowRecipient) 检查其类型和内容。
// dd($rowRecipient);
// 防御性检查
if (is_object($rowRecipient)) {
Mail::to($rowRecipient->email)->send(new DailyActivityReport2($rowRecipient));
} else {
// 记录日志或跳过,处理非对象情况
\Log::warning('Skipping non-object recipient: ' . json_encode($rowRecipient));
}
}
}排查建议:
即使传入的变量是一个有效的对象,如果在类的构造函数中,你试图将传入对象的属性值赋给局部变量而非类的成员属性,那么后续在类内部访问这些属性时,它们将仍为 null。如果再尝试对这些 null 属性进行对象操作,就会再次触发“Trying to get property 'X' of non-object”错误。
错误示例 (Mailable类 DailyActivityReport2 的构造函数):
class DailyActivityReport2 extends Mailable
{
// ... 声明公共属性
public $coID;
public $companyName;
// ... 其他属性声明
public function __construct($rowRecipient)
{
// 错误:这里将值赋给了局部变量 $coID,而非类的成员属性 $this->coID
$coID = $rowRecipient->coID;
$companyName = $rowRecipient->companyName;
// ... 其他属性赋值
// 即使 $rowRecipient 是一个有效的对象,
// 这里的赋值操作也只是创建了局部变量,类的成员属性 $this->coID 依然是 null。
// 后续在 Mailable 的 build() 方法中如果访问 $this->coID->someProperty 就会报错。
}
// ... build 方法或其他使用类属性的地方
}正确示例 (Mailable类 DailyActivityReport2 的构造函数):
class DailyActivityReport2 extends Mailable
{
use Queueable, SerializesModels;
// 声明公共属性,这些属性将在视图中可用
public $coID;
public $companyName;
public $product;
public $rEmpID;
public $rLname;
public $rFname;
public $rEmail;
public $rAccessTeamID;
public $rAccessAgencyID;
public $rAccessProfileID;
public $rAccessTeams;
public $rModules; // 注意这里可能需要进一步处理,例如 json_decode
/**
* Create a new message instance.
*
* @param object $rowRecipient 从数据库查询获取的行对象
* @return void
*/
public function __construct(object $rowRecipient)
{
// 确保 $rowRecipient 是一个对象
if (!is_object($rowRecipient)) {
// 抛出异常或记录错误,不应继续执行
throw new \InvalidArgumentException("Expected an object for rowRecipient, but received " . gettype($rowRecipient));
}
// 正确:使用 $this-> 关键字将值赋给类的成员属性
$this->coID = $rowRecipient->coID ?? null; // 使用 null 合并运算符提供默认值
$this->companyName = $rowRecipient->companyName ?? null;
$this->product = $rowRecipient->product ?? null;
$this->rEmpID = $rowRecipient->empID ?? null;
$this->rLname = $rowRecipient->lname ?? null;
$this->rFname = $rowRecipient->fname ?? null;
$this->rEmail = $rowRecipient->email ?? null;
$this->rAccessTeamID = $rowRecipient->teamID ?? null;
$this->rAccessAgencyID = $rowRecipient->agencyID ?? null;
$this->rAccessProfileID = $rowRecipient->accessProfileID ?? null;
$this->rAccessTeams = $rowRecipient->accessTeams ?? null;
// 对于需要特殊处理的属性,例如 JSON 解码
$this->rModules = isset($rowRecipient->modules) ? json_decode($rowRecipient->modules) : null;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->view('emails.daily-activity-report')
->with([
'companyName' => $this->companyName,
'product' => $this->product,
// ... 其他属性
]);
}
}解释: 在PHP中,$variable = value; 默认是创建一个局部变量。要访问或修改类的成员属性,必须使用 $this->propertyName 语法。混淆这两者是新手常犯的错误。
为了避免“Trying to get property 'X' of non-object”这类错误,并提高代码的健壮性,可以遵循以下实践:
始终使用 $this->: 在类的构造函数或任何方法中,当你想引用或赋值类的成员属性时,务必使用 $this->propertyName。
构造器属性提升 (Constructor Property Promotion): PHP 8 引入的语法糖,可以简化构造函数中属性的声明和赋值。
class DailyActivityReport2 extends Mailable
{
// ... use 声明
public function __construct(
public ?int $coID = null, // 声明并初始化为可空整数
public ?string $companyName = null,
// ... 其他属性
public ?object $rModules = null // 注意这里如果 json_decode 返回对象
) {
// 假设 $rowRecipient 是一个 StdClass 对象
// 实际使用时,你需要将 $rowRecipient 的属性逐一传入
// 或者创建一个 DTO 来封装这些数据
// 这里的例子为了展示构造器属性提升,假设传入的参数就是最终的属性值
}
// ... build 方法
}在实际场景中,你可能需要将 $rowRecipient 转换为 DTO 或直接从 $rowRecipient 提取值作为构造函数的参数。
“Trying to get property 'X' of non-object”错误是PHP开发中常见的运行时问题,通常源于对变量类型的不当假设。解决和避免此类错误的关键在于:
通过遵循这些最佳实践,你将能够编写出更加健壮、可维护且不易出错的PHP和Laravel应用程序。
以上就是PHP/Laravel中“尝试获取非对象属性”错误的深度解析与解决方案的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号