Environment: PHP 7.3, Laravel 5.6
Problem: empty()
and isset()
are returning an incorrect result when the code runs in a browser, but the correct result when run over a Tinker command line session.
Expected Behavior:
isset()
to return true
when the property exists, false
when it does notempty()
to return true
when the property exists and is not null
, false
otherwiseExample: empty()
if(!empty($practiceArea->hero_video)) {
... some HTML
}
This !empty
always evaluates to false
, even though $practiceArea->hero_video
is set and I can see its value through echo
or var_dump
.
And empty($practiceArea->hero_video
) always evaluates to true
, as I learned after unsuccessfully trying the alternative:
if(empty($practiceArea->hero_video) === false) {
Example: isset()
isset($practiceArea->hero_video)
always incorrectly returns false
.
Current Hacky Workaround:
$video = $practiceArea->hero_video;
if(!empty($video)) {
... some HTML
}
This works exactly as expected - $video
takes the value of $practiceArea->hero_video
, then !empty($video)
returns true
if we have a value and false
if the value is null
.
Examples of expected result in Tinker session:
>>> $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()
also works as expected in Tinker:
>>> isset($pa->hero_video)
=> true
>>> !isset($pa->hero_video)
=> false
Reproducing:
I assume that our PracticeArea
class is using magic getters, because it extends Laravel 5.6's Model class, which does include __get
and __isset
methods.
Below is the abridged PracticeArea
class. Happy to post the whole thing, but there are no methods or properties relevant to this.
<?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) "
isset()
on non-public class properties need an implementation of public function __isset()
in the class to work properly.
http://php.net/manual/en/language.oop5.overloading.php#object.isset
__isset()
is triggered by callingisset()
orempty()
on inaccessible properties.
Your specific problem is coming from the implementation in Laravel:
public function __isset($key)
{
return $this->offsetExists($key);
}
public function offsetExists($offset)
{
return ! is_null($this->getAttribute($offset));
}
The method getAttribute()
does not inspect all class properties plus it checks for ! is_null
which is not fully equivalent to isset()
/ empty()
.
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);
}
I would try to investigate the content of the $attributes
property from that Trait.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With