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
中 找到了答案,
PHP 7 has fixed a bug with __isset which affects both the native isset and empty methods. This causes specific issues with checking isset or empty on relations in Eloquent. In PHP 7 checking if a property exists on an unloaded relation, for example isset($this->relation->id) is always returning false because unlike PHP 5.6, PHP 7 is now checking the offset of each attribute before chaining to the next one. In PHP 5.6 it would eager load the relation without checking the offset. This change brings back the intended behavior of the core Eloquent model __isset method for PHP 7 so it works like it did in PHP 5.6. For reference, please check the following link, specifically Nikita Popov's comment (core PHP dev) - https://bugs.php.net/bug.php?id=69659
大致上是 php7 isset 判斷的時候,會依次判斷。php5.6 則會預載入關係。其實 laravel 也早就做了相關的處理,所以升級 laravel 後,自然也就沒有這個問題了。
以上就是解決升級php7後isset方法始終為 false的問題的詳細內容,更多請關注TW511.COM其它相關文章!