【问题标题】:empty() and isset() returning incorrect result for properties of an object - PHP 7.3, Laravel 5.6empty() 和 isset() 为对象的属性返回不正确的结果 - PHP 7.3、Laravel 5.6
【发布时间】:2019-03-19 15:48:02
【问题描述】:

环境: PHP 7.3,Laravel 5.6

问题: empty()isset() 在代码在浏览器中运行时返回不正确的结果,但在 Tinker 命令行会话中运行时返回正确的结果。


预期行为:

  • isset() 在属性存在时返回true,在属性不存在时返回false
  • empty() 返回 true 当属性存在且不为 null,否则返回 false

示例:empty()

if(!empty($practiceArea->hero_video)) { 
   ... some HTML
}

这个!empty 总是计算为false,即使设置了$practiceArea->hero_video 并且我可以通过echovar_dump 看到它的值。

empty($practiceArea->hero_video) 总是评估为true,正如我在尝试替代方案失败后了解到的那样:

if(empty($practiceArea->hero_video) === false) {

示例:isset()

isset($practiceArea->hero_video) 总是错误地返回 false


当前的 Hacky 解决方法:

$video = $practiceArea->hero_video;
if(!empty($video)) { 
   ... some HTML
}

这完全符合预期 - $video 获取 $practiceArea->hero_video 的值,然后 !empty($video) 如果我们有值则返回 true,如果值为 false,则返回 false


Tinker 会话中的预期结果示例:

>>> $pa = PracticeArea::find(11)
>>> ... an object is returned
>>> $pa->hero_video
=> "//www.youtube.com/embed/0qisGSwZym4"
>>> if(empty($pa->hero_video)) echo "Empty"; else echo "Not empty";
Not empty
>>> if(!empty($pa->hero_video)) echo "Not empty"; else echo "Empty";
Not empty

isset() 在 Tinker 中也可以正常工作:

>>> isset($pa->hero_video)
=> true
>>> !isset($pa->hero_video)
=> false

复制:

我假设我们的 PracticeArea 类正在使用魔法 getter,因为它扩展了 Laravel 5.6 的 Model 类,其中确实包括 __get__isset 方法。

下面是删节的PracticeArea 类。很高兴发布整个内容,但没有与此相关的方法或属性。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Traits\Translatable;

class PracticeArea extends Model
{

    protected $table = 'practice_areas';

}


var_dump($practiceAreas)

object(App\PracticeArea)#506 (29) { 
    ["translatable":protected]=> array(5) { 
        [0]=> string(4) "name" 
        [1]=> string(11) "description" 
        [2]=> string(7) "heading" 
        [3]=> string(4) "body" 
        [4]=> string(4) "slug" 
    } 
    ["table":protected]=> string(14) "practice_areas" 
    ["fillable":protected]=> array(11) { 
        [0]=> string(25) "practice_area_category_id" 
        [1]=> string(11) "metadata_id" 
        [2]=> string(4) "name" 
        [3]=> string(11) "description" 
        [4]=> string(7) "heading" 
        [5]=> string(4) "body" 
        [6]=> string(10) "sort_order" 
        [7]=> string(9) "published" 
        [8]=> string(10) "hero_video" 
        [9]=> string(10) "hero_image" 
        [10]=> string(4) "slug" 
    } 
    ["translates":protected]=> array(5) { 
        [0]=> string(4) "name" 
        [1]=> string(11) "description"
        [2]=> string(7) "heading" 
        [3]=> string(4) "body" 
        [4]=> string(4) "slug" 
    } 
    ["translate_relation":protected]=> string(14) "practice_areas" 
    ["connection":protected]=> string(5) "mysql" 
    ["primaryKey":protected]=> string(2) "id" 
    ["keyType":protected]=> string(3) "int" 
    ["incrementing"]=> bool(true) 
    ["with":protected]=> array(0) { } 
    ["withCount":protected]=> array(0) { } 
    ["perPage":protected]=> int(15) 
    ["exists"]=> bool(true) 
    ["wasRecentlyCreated"]=> bool(false) 
    ["attributes":protected]=> array(15) { 
        ["id"]=> int(11) 
        ["practice_area_category_id"]=> int(1) 
        ["metadata_id"]=> int(26) 
        ["name"]=> string(19) "Workplace Accidents" 
        ["description"]=> string(30) "Workplace injuries description" 
        ["heading"]=> string(30) "Workplace Accidents & Injuries" 
        ["body"]=> string(1246) "

【问题讨论】:

  • 出于兴趣,如果您创建了一个公共 get 方法并相应地使用 isset/empty 会发生什么?
  • 虽然这可能是一个有趣的问题,尤其是环境之间的差异……如果$video = $practiceArea-&gt;hero_video 工作没有错误,即$practiceArea-&gt;hero_video 保证不会引发任何关于未定义属性的错误(Eloquent 模型可能会,我有不知道...!?),那么您根本不需要也不应该使用emptyisset
  • @treyBake 我将在今天晚些时候尝试并用结果更新帖子。
  • @deceze 在 hero_video 为空的情况下,我们需要渲染一个不同的 HTML 块,它使用替代的 hero_image
  • 所以,isset/empty 在有魔法吸气剂的类上需要类的合作才能正常工作。 Eloquent 似乎有问题,或者它假设您永远不需要将 isset/empty 与它的属性一起使用,因为它总是会为任何给定属性返回 a value 并且永远不会引发错误。那么你不应该使用isset/empty,而只是检查它的值,比如if (!$practiceArea-&gt;hero_video)。这将产生与您期望 empty 完全相同的效果。

标签: php laravel laravel-5 php-7.3


【解决方案1】:

isset() on non-public 类属性需要在类中实现public function __isset() 才能正常工作。

http://php.net/manual/en/language.oop5.overloading.php#object.isset

__isset() 通过调用isset()empty() on 触发 无法访问的属性。

您的具体问题来自 Laravel 中的实现:

public function __isset($key)
{
    return $this->offsetExists($key);
}

public function offsetExists($offset)
{
    return ! is_null($this->getAttribute($offset));
}

getAttribute() 方法不会检查所有类属性,并且它会检查不完全等同于isset() / empty()! is_null

https://github.com/laravel/framework/blob/5.6/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

// If the attribute exists in the attribute array or has a "get" mutator we will
// get the attribute's value. Otherwise, we will proceed as if the developers
// are asking for a relationship's value. This covers both types of values.
if (array_key_exists($key, $this->attributes) ||
    $this->hasGetMutator($key)) {
    return $this->getAttributeValue($key);
}

我会尝试从该 Trait 调查 $attributes 属性的内容。

【讨论】:

  • OP 指出该类是一个 Laravel 模型,其中包含 __isset() 实现
  • @morph 是的,但实施并未涵盖 OP 问题
猜你喜欢
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 2011-06-21
  • 2016-07-05
  • 2016-07-03
  • 2012-07-04
  • 1970-01-01
相关资源
最近更新 更多