How to find if an object is empty or not in PHP.
Following is the code in which $obj is holding XML data. How can I check if it's empty or not?
My code:
$obj = simplexml_load_file($url);
You can cast to an array and then check if it is empty or not
$arr = (array)$obj;
if (!$arr) {
// do stuff
}
Edit: I didn't realize they wanted to specifically check if a SimpleXMLElement object is empty. I left the old answer below
Updated Answer (SimpleXMLElement):
For SimpleXMLElement:
If by empty you mean has no properties:
$obj = simplexml_load_file($url);
if ( !$obj->count() )
{
// no properties
}
OR
$obj = simplexml_load_file($url);
if ( !(array)$obj )
{
// empty array
}
If SimpleXMLElement is one level deep, and by empty you actually mean that it only has properties PHP considers falsey (or no properties):
$obj = simplexml_load_file($url);
if ( !array_filter((array)$obj) )
{
// all properties falsey or no properties at all
}
If SimpleXMLElement is more than one level deep, you can start by converting it to a pure array:
$obj = simplexml_load_file($url);
// `json_decode(json_encode($obj), TRUE)` can be slow because
// you're converting to and from a JSON string.
// I don't know another simple way to do a deep conversion from object to array
$array = json_decode(json_encode($obj), TRUE);
if ( !array_filter($array) )
{
// empty or all properties falsey
}
Old Answer (simple object):
If you want to check if a simple object (type stdClass) is completely empty (no keys/values), you can do the following:
// $obj is type stdClass and we want to check if it's empty
if ( $obj == new stdClass() )
{
echo "Object is empty"; // JSON: {}
}
else
{
echo "Object has properties";
}
Source: http://php.net/manual/en/language.oop5.object-comparison.php
Edit: added example
$one = new stdClass();
$two = (object)array();
var_dump($one == new stdClass()); // TRUE
var_dump($two == new stdClass()); // TRUE
var_dump($one == $two); // TRUE
$two->test = TRUE;
var_dump($two == new stdClass()); // FALSE
var_dump($one == $two); // FALSE
$two->test = FALSE;
var_dump($one == $two); // FALSE
$two->test = NULL;
var_dump($one == $two); // FALSE
$two->test = TRUE;
$one->test = TRUE;
var_dump($one == $two); // TRUE
unset($one->test, $two->test);
var_dump($one == $two); // TRUE
You can cast your object into an array, and test its count like so:
if(count((array)$obj)) {
// doStuff
}
Imagine if the object is not empty and in a way quite big, why would you waste the resources to cast it to array or serialize it...
This is a very easy solution I use in JavaScript. Unlike the mentioned solution that casts an object to array and check if it is empty, or to encode it into JSON, this simple function is very efficient concerning used resources to perform a simple task.
function emptyObj( $obj ) {
foreach ( $obj AS $prop ) {
return FALSE;
}
return TRUE;
}
The solution works in a very simple manner: It wont enter a foreach loop at all if the object is empty and it will return true. If it's not empty it will enter the foreach loop and return false right away, not passing through the whole set.
Using empty() won't work as usual when using it on an object, because the __isset() overloading method will be called instead, if declared.
Therefore you can use count() (if the object is Countable).
Or by using get_object_vars(), e.g.
get_object_vars($obj) ? TRUE : FALSE;
Another possible solution which doesn't need casting to array:
// test setup
class X { private $p = 1; } // private fields only => empty
$obj = new X;
// $obj->x = 1;
// test wrapped into a function
function object_empty( $obj ){
foreach( $obj as $x ) return false;
return true;
}
// inline test
$object_empty = true;
foreach( $obj as $object_empty ){ // value ignored ...
$object_empty = false; // ... because we set it false
break;
}
// test
var_dump( $object_empty, object_empty( $obj ) );
there's no unique safe way to check if an object is empty
php's count() first casts to array, but casting can produce an empty array, depends by how the object is implemented (extensions' objects are often affected by those issues)
in your case you have to use $obj->count();
http://it.php.net/manual/en/simplexmlelement.count.php
(that is not php's count http://www.php.net/count )
in PHP version 8
consider you want to access a property of an object, but you are not sure that the object itself is null or not and it could cause error. in this case you can use Nullsafe operator that introduced in php 8 as follow:
$country = $session?->user?->getAddress()?->country;
If you cast anything in PHP as a (bool), it will tell you right away if the item is an object, primitive type or null. Use the following code:
$obj = simplexml_load_file($url);
if (!(bool)$obj) {
print "This variable is null, 0 or empty";
} else {
print "Variable is an object or a primitive type!";
}
If an object is "empty" or not is a matter of definition, and because it depends on the nature of the object the class represents, it is for the class to define.
PHP itself regards every instance of a class as not empty.
class Test { }
$t = new Test();
var_dump(empty($t));
// results in bool(false)
There cannot be a generic definition for an "empty" object. You might argue in the above example the result of empty() should be true, because the object does not represent any content. But how is PHP to know? Some objects are never meant to represent content (think factories for instance), others always represent a meaningful value (think new DateTime()).
In short, you will have to come up with your own criteria for a specific object, and test them accordingly, either from outside the object or from a self-written isEmpty() method in the object.
I was using a json_decode of a string in post request. None of the above worked for me, in the end I used this:
$post_vals = json_decode($_POST['stuff']);
if(json_encode($post_vals->object) != '{}')
{
// its not empty
}
Simply check if object type is null or not.
if( $obj !== null )
{
// DO YOUR WORK
}
count($the_object) > 0 this is working and can be use for array too
Based on this answer from kenorb, here's another one-liner for objects with public vars:
if (!empty(get_object_vars($myObj))) { ... }
Edit: Thanks to #mickmackusa's comment below - below is a more succinct one-liner, since this converts the object to an associative array (of accessible properties), and an empty array is falsy in PHP.
if (get_object_vars($myObj)) { ... }
Just to reiterate - this is for objects with public/accessible variables. Objects with static, private, or protected vars will render false, which may be unexpected. See https://www.php.net/manual/en/function.get-object-vars.php
$array = array_filter($array);
if(!empty($array)) {
echo "not empty";
}
or
if(count($array) > 0) {
echo 'Error';
} else {
echo 'No Error';
}
Related
I get an XML response from an API and I use simplexml_load_string to convert it to an object in PHP. I then store the object into a mongo database directly and it works perfect. The issue is since it comes from XML all the nodes are of type "string" in mongo. Is there a fancy or simple way to loop through all the nodes in the PHP object and convert to integer or float or boolean? If I pull out all the nodes manually I can use "intval" and "floatval" but I am looking to see if it may be possible to do this automatically based on the content. ie. Loop through all the nodes regardless of depth and do a preg_match for 0-9 to set the item to type "int". If 0-9 w/ . set to float. If true/false/0/1 set to bool. Leave the rest strings. Any ideas?
$this->response_object = simplexml_load_string($xml);
Values in SimpleXML are always of type string within PHP. And due to the magic nature of the SimpleXMLElement class, you can not change that by extending from it.
However, you can extend from SimpleXMLElement and add a function called typecastValue() (exemplary) which does the work. You then can specify with simplexml_load_string that you want to use that class instead of the default SimpleXMLElement class.
class MyElement extends SimpleXMLElement
{
public function typecastValue() {
$value = trim($this);
// check if integer, set as float
if (preg_match('/^[0-9]{1,}$/', $value)){
return floatval($value);
}
// check if float/double
if (preg_match('/^[0-9\.]{1,}$/', $value)){
return floatval($value);
}
// check if boolean
if (preg_match('/(false|true)/i', $value)){
return (boolean)$value;
}
// all else leave as string
return $value;
}
}
As you can see, the code is very similar to your typecast function above, it just uses $this to obtain the original value.
Functions like xml_object_to_array are still generally superfluous, as the parsing is already done and you're more concerned about accessing and serializing the date in the XML into an array (I suspect this is due to JSON requirements of Mongodb but I don't know). If so, PHP JSON Serialization would/could be more appropriate, for SimpleXMLElement we have existing material on the site already.
Json Encode or Serialize an XML
I think I found my own answer (unless you have a more elegant way)...
function xml_object_to_array($xml) {
if ($xml instanceof SimpleXMLElement) {
$children = $xml->children();
$return = null;
}
foreach ($children as $element => $value) {
if ($value instanceof SimpleXMLElement) {
$values = (array)$value->children();
if (count($values) > 0) {
$return[$element] = xml_object_to_array($value);
} else {
if (!isset($return[$element])) {
$return[$element] = typecast_value($value);
} else {
if (!is_array($return[$element])) {
$return[$element] = array($return[$element], typecast_value($value));
} else {
$return[$element][] = typecast_value($value);
}
}
}
}
}
if (is_array($return)) {
return $return;
} else {
return false;
}
}
// auto typecast value for mongo storage
function typecast_value($value){
$value = trim($value);
// check if integer, set as float
if(preg_match('/^[0-9]{1,}$/', $value)){
return floatval($value);
}
// check if float/double
if(preg_match('/^[0-9\.]{1,}$/', $value)){
return floatval($value);
}
// check if boolean
if(preg_match('/(false|true)/i', $value)){
return (boolean)$value;
}
// all else leave as string
return $value;
}
I wrote some program to check the value in an array.
var_dump($profileuser);//NULL
$profileuser = get_user_to_edit($user_id);//fetch the value of $profileuser
var_dump($profileuser);//does not print the value of $profileuser->user_url
//nor by print_r($profileuser)
if(isset($profileuser->user_url))
echo $profileuser->user_url;//printed!!!!How is it possible??
Could somebody can explain how this happened?
background:
I modified the kernel of wordpress.
This happened when I modified the file of wp-admin/user-edit.php.
You say it's an array, but you're accessing it as an object ($obj->foo rather than $arr['foo']), so it's most likely an object (actually it is - get_user_to_edit returns a WP_User). It could easily contain the magic __get and __isset methods that would lead to this behaviour:
<?php
class User {
public $id = 'foo';
public function __get($var) {
if ($var === 'user_url') {
return 'I am right here!';
}
}
public function __isset($var) {
if ($var === 'user_url') {
return true;
}
return false;
}
}
$user = new User();
print_r($user);
/*
User Object
(
[id] => foo
)
*/
var_dump( isset($user->user_url) ); // bool(true)
var_dump( $user->user_url ); // string(16) "I am right here!"
DEMO
One possibility is that $profileuser is an Object that behaves as an array and not an array itself.
This is possible with interface ArrayAccess. In this case, isset() would return true and you might not see it when you do var_dump($profileuser);.
When you want an object to behave like an array, you need to implement some methods which tell your object what to do when people use it as if it were an array. In that case, you could even create an Object that, when accessed as an array, fetches some webservice and return the value. That may be why you are not seeing those values when you var_dump your variable.
I thinks it's not possible, I've created test code and var_dump behaves correctly. Are you 100% sure you don't have any typo in your code? I remind variables in PHP are case sensitive
<?php
$profileuser = null;
class User
{
public $user_url;
}
function get_user_to_edit($id) {
$x = new User();
$x->user_url = 'vcv';
return $x;
}
var_dump($profileuser);//NULL
$user_id = 10;
$profileuser = get_user_to_edit($user_id);//fetch the value of $profileuser
var_dump($profileuser);//does not print the value of $profileuser->user_url
//nor by print_r($profileuser)
if(isset($profileuser->user_url))
echo $profileuser->user_url;//printed!!!!How does it possible??
Result is:
null
object(User)[1]
public 'user_url' => string 'vcv' (length=3)
vcv
I see there are about a hundred different questions on here for Creating default object from empty value. None of them really seem to help with my issue.
I am assigning a child object of the same class in a method. This triggers the Creating default object from empty value error.
class myClass {
function __construct($rootName, $allowHTML = false, $endTag = true) {
$this->rootElement = $rootName;
$this->elements = array();
$this->attributes = array();
$this->value = "";
$this->allowHTML = $allowHTML;
$this->endTag = $endTag;
$this->styles = array();
$this->childID = 0;
}
// ... OTHER METHODS HERE (ALL PROPERTIES DECLARED)
function assignElement(&$theElement) {
// Get the index.
$index = count($this->elements);
// Assign the element.
$this->elements[$index] = $theElement;
if (get_class($theElement) == get_class($this)) {
$this->elements[$index]->childID = $index;
}
// Return the node.
return $this->elements[$index];
}
}
The error occurs on $this->elements[$index]->childID = $index;. How do I handle this properly?
Seems like you are passing NULL to the assignElement. get_class called with no arguments or null as argument, returns class of the object where it is defined, so your if conditions is true for null values. You should use is_object first.
Is it possible to do in one line calling a method that returns an array() and directly get a value of this array ?
For example, instead of :
$response = $var->getResponse()->getResponseInfo();
$http_code = $response['http_code'];
echo $http_code;
Do something like this :
echo $var->getResponse()->getResponseInfo()['http_code'];
This example does not work, I get a syntax error.
If you're using >= PHP 5.4, you can.
Otherwise, you'll need to use a new variable.
What you can do is to pass the directly to your function. Your function should be such that if a variable name is passed to it, it should the value of that variable, else an array with all variables values.
You can do it as:
<?php
// pass your variable to the function getResponseInfo, for which you want the value.
echo $var->getResponse()->getResponseInfo('http_code');
?>
Your function:
<?php
// by default, it returns an array of all variables. If a variable name is passed, it returns just that value.
function getResponseInfo( $var=null ) {
// create your array as usual. let's assume it's $result
/*
$result = array( 'http_code'=>200,'http_status'=>'ok','content_length'=>1589 );
*/
if( isset( $var ) && array_key_exists( $var, $result ) ) {
return $result[ $var ];
} else {
return $result;
}
}
?>
Hope it helps.
Language itself does not support that for an array.
In case you can change what getResponseInfo() return:
You can create simple class, which will have array as an constructor parameter. Then define magical getter which will be just pulling the keys from the instance array
function __get($key)
{
return #content[$key]
}
Then you'll be able to do
echo $var->getResponse()->getResponseInfo()->http_code;
// or
echo $var->getResponse()->getResponseInfo()->$keyWhichIWant;
What i wrote is just proposal. The real __get method should have some check if the exists and so
I'm reading JSON data with PHP and that data contains empty objects (like {}). So the problem is, I have to handle the case when object is empty in different manner but I can't find good enough way to do the check. empty(get_object_vars(object)) looks too scary and very inefficient. Is there good way to do the check?
How many objects are you unserializing? Unless empty(get_object_vars($object)) or casting to array proves to be a major slowdown/bottleneck, I wouldn't worry about it – Greg's solution is just fine.
I'd suggest using the the $associative flag when decoding the JSON data, though:
json_decode($data, true)
This decodes JSON objects as plain old PHP arrays instead of as stdClass objects. Then you can check for empty objects using empty() and create objects of a user-defined class instead of using stdClass, which is probably a good idea in the long run.
You could cast it to an array (unfortunately you can't do this within a call to empty():
$x = (array)$obj;
if (empty($x))
...
Or cast to an array and count():
if (count((array)$obj))
...
Try without using empty() which is:
get_object_vars($obj) ? TRUE : FALSE;
On PHP docs we can read the note:
When using empty() on inaccessible object properties, the __isset() overloading method will be called, if declared.
Which means when using empty() on an object which is having __get() method, it will always return True.
I had to tell if an object was empty or not, but I also had to ignore private and protected properties, so I made this little function with which you can do this.
function empty_obj(&$object, $ignore_private = true, $ignore_protected = true) {
$obj_name = get_class($object);
$obj = (array)$object;
foreach(array_keys($obj) as $prop) {
$is_private = $is_protected = false;
$prop = preg_replace("/[^\w*]/", '', $prop);
$prop_name = str_replace(array($obj_name, '*'), '', $prop);
if(preg_match("~^$obj_name$prop_name$~", $prop))
$is_private = true;
if(preg_match("~^\*$prop_name$~", $prop))
$is_protected = true;
if(!$is_private || !$is_protected || ($is_private && !$ignore_private) || ($is_protected && !$ignore_protected))
return;
}
return true;
}
I am not sure if this is more or less effective than casting to an array but I would guess more. You could just start to loop the object and as soon as you find something you have an answer and stop looping.
function is_obj_empty($obj){
if( is_null($obj) ){
return true;
}
foreach( $obj as $key => $val ){
return false;
}
return true;
}