PHP 属性比较是否会导致删除对象上的所有属性?

问题描述 投票:0回答:1

我遇到了一个非常奇怪的问题,我最好的猜测是这是 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');

PostController@更新

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@编辑

调用 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)
结果。

Post object before comparison call

这里再次从

if
块内调用它。

Post object after the comparison call

有没有人曾经见过这样的事情,或者有任何想法可能导致它?

php laravel
1个回答
0
投票

在策略中,类型有时不正确。使用宽松的比较。

$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()};

https://github.com/laravel/jetstream/blob/30bde139ca1c41d10a58c67f8daa2e8cd3a0be93/src/HasTeams.php#L105

© www.soinside.com 2019 - 2024. All rights reserved.