empty() returns wrong result - php

$user = new User(1);
var_dump($user->ID);
if (empty($user->ID))
echo "empty";
// output string(2) "77" empty
So why is empty() returning true even when $user var is not empty?
The relevant parts of my User class:
class User {
protected $data = null;
public function __construct($userID) {
// sql select
$this->data = $sqlResult;
}
// ...
public function __get($name) {
if (isset($this->data[$name]))
return $this->data[$name];
else
return null;
}
}
UPDATE:
So I updated my User class and added the __isset() method
public function __isset($name) {
if (isset($this->data[$name]) && !empty($this->data[$name]))
return true;
else
return false;
}
This leads me to another problem:
When calling empty() on my not empty var empty($user->ID) it will return false, but when using isset($user->ID) on a declared var which is empty (e.g. $user->ID = '') it will also return false, because isset() will call __isset() inside the class, right?
Is there a way to fix this behaviour?
PHP notes, that I should copy the overloaded property into a local variable, which seems too much paperwork for me ;)

empty() doesn't call __get(). You need to implement __isset().

Quoting from the manual:
Note:
It is not possible to use overloaded properties in other language constructs than isset(). This means if empty() is called on an overloaded property, the overloaded method is not called.

According to the docs, you should overload __isset() for empty to work

Related

empty() not catching a string? [duplicate]

I have a "getter" method like
function getStuff($stuff){
return 'something';
}
if I check it with empty($this->stuff), I always get FALSE, but I know $this->stuff returns data, because it works with echo.
and if I check it with !isset($this->stuff) I get the correct value and the condition is never executed...
here's the test code:
class FooBase{
public function __get($name){
$getter = 'get'.ucfirst($name);
if(method_exists($this, $getter)) return $this->$getter();
throw new Exception("Property {$getter} is not defined.");
}
}
class Foo extends FooBase{
private $my_stuff;
public function getStuff(){
if(!$this->my_stuff) $this->my_stuff = 'whatever';
return $this->my_stuff;
}
}
$foo = new Foo();
echo $foo->stuff;
if(empty($foo->stuff)) echo 'but its not empty:(';
if($foo->stuff) echo 'see?';
empty() will call __isset() first, and only if it returns true will it call __get().
Implement __isset() and make it return true for every magic property that you support.
function __isset($name)
{
$getter = 'get' . ucfirst($name);
return method_exists($this, $getter);
}
Magic getters are not called when checking with empty. The value really does not exist, so empty returns true. You will need to implement __isset as well to make that work correctly.
__isset() is triggered by calling isset() or empty() on inaccessible properties.
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
PHP's magic get method is named __get(). $this->stuff will not call getStuff(). Try this:
public function __get($property) {
if ($property == 'stuff') {
return $this->getStuff();
}
}

Possible to implement object handling of empty()

I know we can implement PHP's countable interface to determine how the function count() works as well as the Iterator interface for using an object like an array.
Is it possible to implement some kind of interface (or any other way) to change the behavior of empty() on an object?
Essentially, this is what I would like to be able to do:
<?php
class test {
function __empty() {
if (count($this->data) > 0) {
return false;
}
return true;
}
}
Just a nice to have!
No there is not. The iterator behavior and count behaviors have no sense over an object; that's why you can override them. The default behavior of empty() applied to an object has a meaning instead: is it an instance of an object or is it NULL?; that's why you can't override it.
You can instead:
create a method inside the object called isEmpty() and implement it there
create a global function emptyObj() and implement it there
No. PHP does not have it. You can request for such feature on wiki.php.net. In the meantime you can roll your own.
interface Empty_Checkable{
function isempty();
}
class test implements Empty_Checkable{
function isempty() {
if (count($this->data) > 0) {
return false;
}
return true;
}
}
This is not possible on the object directly.
If you need to do it, I would suggest implementing the Countable interface, and then instead of calling empty($foo), call count($foo) == 0...
However, for properties, it is possible using a combination of two magic methods: __isset and __get. For example:
class Foo {
protected $bar = false;
protected $baz = true;
public function __get($key) {
return $this->$key;
}
public function __isset($key) {
return isset($this->$key);
}
}
That results in:
empty($foo->abc); // true, isset returns false
empty($foo->bar); // true, isset returns true, but get returns false value
empty($foo->baz); // false, isset returns true, and get returns a true value
So no, it's not possible with a single method handler, but with the combination of the two magic methods, it works fine...
It is possible to implement Countable
class MyCollection extends stdClass implements Serializable, ArrayAccess, Countable, Iterator, JsonSerializable
{
public function count() {
return count($this->array);
}
}
and use !count() instead of empty() like
if (!count($myList)) {
echo "List is empty!";
}

__isset() magic function on the Object it self

I know you can do this
class Object
{
private $ar;
public function __isset($name)
{
return isset($this->ar[$name]);
}
}
which can then be used to do the following
$obj = new Object();
if (isset($obj->name)) { /* ... */ }
However is there a way to do this
$obj = new Object();
if (isset($obj)) { /* .... */ }
Where i can control the return of $obj status using the __isset() magic method on the object it self.
You could only define a new global function myIsset() or something like it to do this.
function myIsset($obj = NULL)
{
...
}
When checking the variable $obj with isset PHP doesn't interact with the object that might be referenced by the variable at all.
You cannot, because it would not make any sense (at least not in the way isset() is meant to be used). So isset($obj) is always true as long as it points to some object and not NULL/undefined.
Magic method __isset is not intended to be used that way.
According to PHP manual:
"__isset() is triggered by calling isset() or empty() on inaccessible properties."

Using php's magic function inside another function does not work

I want to use magic function __set() and __get() for storing SQL data inside a php5 class and I get some strange issue using them inside a function:
Works:
if (!isset($this->sPrimaryKey) || !isset($this->sTable))
return false;
$id = $this->{$this->sPrimaryKey};
if (empty($id))
return false;
echo 'yaay!';
Does not work:
if (!isset($this->sPrimaryKey) || !isset($this->sTable))
return false;
if (empty($this->{$this->sPrimaryKey}))
return false;
echo 'yaay!';
would this be a php bug?
empty() first* calls the __isset() method and only if it returns true the __get() method. i.e. your class has to implement __isset() as well.
E.g.
<?php
class Foo {
public function __isset($name) {
echo "Foo:__isset($name) invoked\n";
return 'bar'===$name;
}
public function __get($name) {
echo "Foo:__get($name) invoked\n";
return 'lalala';
}
}
$foo = new Foo;
var_dump(empty($foo->dummy));
var_dump(empty($foo->bar));
prints
Foo:__isset(dummy) invoked
bool(true)
Foo:__isset(bar) invoked
Foo:__get(bar) invoked
bool(false)
* edit: if it can't "directly" find an accessible property in the object's property hashtable.

How to return TRUE|FALSE from class in PHP

I was wondering why my php program is not returning the correct TRUE FALSE value when the class is included elsewhere
it goes something like this
source: signup.php
class signup
{
function buildProfile()
{
if($logic){
$this->success = TRUE;
}else{
$this->success = FALSE;
}
}
function __construct()
{
$this->success = NULL;
$this->buildProfile
return $this->success;
}
}
and elsewhere I do
include('signup.php');
$signup = new signup();
if($signup){
successFunction();
}else....
but it's not getting $signup == true, it's getting FALSE every time
Constructors always return a new instance of the class. You cannot return any other type of value from a constructor. A better way to structure your code would be something like:
source: signup.php
class Signup
{
public $success;
protected function buildProfile()
{
if($logic){
$this->success = true;
}else{
$this->success = false;
}
}
public function __construct()
{
$this->success = null;
$this->buildProfile();
}
}
Then when you construct the object you could do:
include('signup.php');
$signup = new Signup();
if($signup->success){
successFunction();
}else....
With that here :
$signup = new signup();
You are creating an instance of the class, via its constructor.
A constructor is not a normal function : I don't think it can actually "return" anything : it is just here to initialize some data in the object upon its instanciation.
With that, you $signup variable is an object ; an instance of class signup ; it's not any other kind of value, whatever return instruction you'll write in your constructor.
Quoting from wikipedia's Constructor page :
A constructor is similar to an
instance method, but it differs from a
method in that it never has an
explicit return type, it is not
inherited, and usually has different
rules for scope modifiers.
By the way, don't write things like this:
if($logic) {
$this->success = true;
}else{
$this->success = false;
}
write things like this:
$this->success = $logic;
You cannot return a value from a constructor.
A constructor's sole purpose is to initialize an object. In your example, $signup is your object, it's not a "return value" from the constructor.
You are attempting to imitate a "default functor", a feature that is not present in PHP until 5.3, e.g. you are trying to evaluate an object as if it were a function (as said above, ``new'' always returns you object instances). Objects aren't functions, so a default functor is an instance method that gets automagically executed when its object is invoked as a function.
Either way, the correct solution is in the top answer.
Perhaps a static method would be more appropriate?
http://php.net/manual/en/language.oop5.static.php
include('signup.php');
if(Signup::buildProfile()){
successFunction();
}else....

Categories