我遇到了一个非常奇怪的问题,我最好的猜测是这是 PHP 本身的一个错误。当比较 (
===
) 一个对象的属性值与另一个对象的属性值时,其中一个对象的所有属性值都会被删除。
PHP 8.3.2-1+0~20240120.16+debian11~1.gbpb43448
Laravel Framework 11.4.0
mySQL 8.0.33-0ubuntu0.20.04.2
我正在编辑
Post
模型,并在表单提交上运行 update
方法
路由模型绑定按预期工作,并且调用了正确的控制器方法。
Route::patch('/posts/{id}/update', [PostController::class, 'update'])
->name('post.update');
public function update(UpdatePostRequest $request, Post $post) :RedirectResponse
{
// A quick test here that will become relevant in a moment
// dd(request()->user()->id === $post->user_id); // true
// Results in 403
if (request()->user()->cannot('edit', $post))
abort(403);
.
.
.
}
调用 PostPolicy 类来检查用户是否可以编辑帖子。尽管所比较的值是相同的,但
if
语句是错误的。
/**
* Determine if "$user" can perform "edit" on "$post"
*/
public function edit(User $user, Post $post) :bool
{
if ($post->user_id === $user->id) {
// Expecting this to return
return $user->can('edit.own_posts');
}
else{
// Always gets returned
return $user->can('edit.posts');
}
}
注意:我已验证所有角色和权限均已正确分配,尽管这与我所看到的问题并不真正相关。
在上面的函数中,在
$user
语句之前检查 $post
和 if
的值会准确地产生预期的值...$post->user_id
严格等于 (===
) 于 $user->id
。
但是,从
$post
语句块中检查 if
的值,会发现 $post
上的所有属性都是空的。他们都消失了。
以下是各种
dd()
(dump()
和 die()
)调用的结果。
public function edit(User $user, Post $post) :bool
{
dd($user->id); // int 112
dd($post->user_id); // int 112
dd($user->id == $post->user_id); // true
dd($user->id === $post->user_id); // true
// What if accessing the property is what causes it to become null?
// Let's dump it twice.
dd($post->user_id, $post->user_id) // int 112, int 112
// After the comparison, all properties of
// $post are empty
if ($post->user_id === $user->id) {
return $user->can('edit.own_posts');
}
else{
dd($user->id); // int 112
dd($post->user_id); // null
dd($user->id == $post->user_id); // false
dd($user->id === $post->user_id); // false
return $user->can('edit.posts');
}
}
这个真的让我很失望。当且仅当我将
dd()
放入 if
块内时,它将像比较结果为 true
一样执行,但如果我删除 dd()
,则不会执行。
public function edit(User $user, Post $post) :bool
{
if ($post->user_id === $user->id) {
// This line executes when present. Removing it will cause
// the `else` block to execute.
dd($user->id, $post->user_id); // int 112, null
return $user->can('edit.own_posts');
}
else{
// This line only executes if you remove the dd() above
return $user->can('edit.posts');
}
}
无论我做什么,第二个
return
语句是我唯一能得到的。但只是为了好玩,让我们尝试颠倒逻辑。
public function edit(User $user, Post $post) :bool
{
if ($post->user_id !== $user->id) {
// Always executes
return $user->can('edit.posts');
}
else{
return $user->can('edit.own_posts');
}
}
为了直观参考,这是比较调用之前的
dd($post)
结果。
这里再次从
if
块内调用它。
有没有人曾经见过这样的事情,或者有任何想法可能导致它?
在策略中,类型有时不正确。使用宽松的比较。
$post->user_id == $user->id
//or
(int) $post->user_id === (int) $user->id
//or
$post->user->is($user)
甚至 Laravel 官方代码也使用
==
。
return $this->id == $team->{$this->getForeignKey()};