升级 php7 后 isset 不太对了

公司升级 php7 后出现了一个问题

类似这样 isset($post->user->name) 始终为 false

之前的 php 5.6 就很正常

laravel 版本是 5.1.35(很久没升级了)

先看看 isset

isset 用来检测变量是否设置

首先我们来看官方的一个例子

大致上是下面这个意思

<?php
class Post
{
    protected $attributes = ['content' => 'foobar'];
    public function __get($key)
    {
        if (isset($this->attributes[$key])) {
            return $this->attributes[$key];
        }
    }
}
$post = new Post();
echo isset($post->content);  // false
登录后复制

上面这个例子将永远返回 false,因为 foo 并不是 Post 的属性,而是 __get 取出来的

魔术方法 __isset

那么怎么解决上面那个问题呢?使用魔术方法

<?PHP
class Post
{
    protected $attributes = ['content' => 'foobar'];
    public function __get($key)
    {
        if (isset($this->attributes[$key])) {
            return $this->attributes[$key];
        }
    }
    public function __isset($key)
    {
        if (isset($this->attributes[$key])) {
            return true;
        }
        return false;
    }
}
$post = new Post();
echo isset($post->content);   //true
登录后复制

类似 Eloquent 的例子

看着 laravel 5.1.35 的代码,我们自己写一个简单的例子

先有一个 Model,简单的实现。__get,__set,__isset

class Model
{
    // 存放属性
    protected $attributes = [];
    // 存放关系
    protected $relations = [];
    public function __get($key)
    {
        if( isset($this->attributes[$key]) ) {
            return $this->attributes[$key];
        }
          // 找到关联的对象,放在关系里面
        if (method_exists($this, $key)) {
              $relation = $this->$method();   
              return $this->relations[$method] = $relation;
        }
    }
    public function __set($k, $v)
    {
        $this->attributes[$k] = $v;
    }
    public function __isset($key)
    {
        if (isset($this->attributes[$key]) || isset($this->relations[$key])) {
            return true;
        }
        return false;
    }
}
登录后复制

然后我们定义一个 Post Moel 和一个 User Moel

class Post extends Model
{
    protected function user()
    {
        $user = new User();
        $user->name = 'user name';
        return $user;
    }
}
class User extends Model
{
}
登录后复制

好了来验证一下 isset

$post = new Post();
echo 'isset 发帖用户:';
echo isset($post->user) ? 'true' : 'false';  // false
echo PHP_EOL;
echo 'isset 发帖用户的名字:';
echo isset($post->user->name) ? 'true' : 'false';  // false
echo PHP_EOL;
echo '发帖用户的名字:';
echo $post->user->name;    // user name
echo PHP_EOL;
echo '再次判断 isset 发帖用户的名字:';
echo isset($post->user->name) ? 'true' : 'false';   // true
echo PHP_EOL;
登录后复制

答案

分析上面的结果,感觉像是 php 7 isset 方法对对象的判断有了变化,如果先执行一次,$post->user->name,也就是将 user 放在 post 的 relations 中,这样 isset ($post->user) 为 true,随后 isset ($post->user->name) 才为 true。

最后在 Eloquent model 的 git log 中 找到了答案,

大致上是 php7 isset 判断的时候,会依次判断。php5.6 则会预加载关系。其实 laravel 也早在 5 月份就做了相关的处理,所以升级 laravel 后,自然也就没有这个问题了。

推荐教程:《PHP7教程》《PHP教程》《Laravel教程

以上就是PHP7中的isset的详细内容,更多请关注Work网其它相关文章!

09-15 03:41