Show all public attributes (name and value) of an object - php

This thread didn't helped me.
If I use
$class_vars = get_class_vars(get_class($this));
foreach ($class_vars as $name => $value) {
echo "$name : $value\n";
}
I get
attrib1_name : attrib2_name : attrib3_name
There are no values. Also a private attribute is shown, which I don't want.
If I use
echo "<pre>";
print_r(get_object_vars($this));
echo "</pre>";
I get
Array
(
[atrrib1_name] => attrib1_value
[attrib2_name] => attrib2_value
)
Here again I have a private attribute and all sub attributes. But this time I have the values. How can I constrain this to one level?
Isn't there a possibility to show all public attributes with their values of an object?

You are seeing non-public properties because get_class_vars works according to current scope. Since you are using $this your code is inside the class, so the non-public properties are accessible from the current scope. The same goes for get_object_vars which is probably a better choice here.
In any case, a good solution would be to move the code that retrieves the property values out of the class.
If you do not want to create a free function for that (why? seriously, reconsider!), you can use a trick that involves an anonymous function:
$getter = function($obj) { return get_object_vars($obj); };
$class_vars = $getter($this);
See it in action.
Update: Since you are in PHP < 5.3.0, you can use this equivalent code:
$getter = create_function('$obj', 'return get_object_vars($obj);');
$class_vars = $getter($this);

You can do this easily with php Reflection api

Extending Mr.Coder's answer, here is a snippet to fetch the public attributes of the object (name and value) as an array
public function getPublicProperties()
{
$results = [];
$reflectionObject = (new ReflectionObject($this));
$properties = $reflectionObject->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
$results[$property->getName()] = $property->getValue($this);
}
return $results;
}

Use get_object_vars.
see: http://dk.php.net/manual/en/function.get-object-vars.php

I Fully recognize what you are trying to achieve so why not have something external like this to help out... (pasted from PHPFiddle)
<?php
final class utils {
public static function getProperties(& $what) {
return get_object_vars($what);
}
}
class ball {
var $name;
private $x, $y;
function __construct($name,$x,$y) {
}
function publicPropsToArray() {
return utils::getProperties($this);
}
function allPropsToArray() {
return get_object_vars($this);
}
}
$ball1 = new ball('henry',5,6);
//$ball2 = new ball('henry',3,4);
echo "<pre>";
print_r($ball1->publicPropsToArray());
echo "\r\n\r\n";
print_r($ball1->allPropsToArray());
echo "\r\n\r\n";
?>
This way I can both access all properties of the object or for something such as a database access layer or similarly for a function that send "safe" data to a view or another un-privileged model I can send just the public properties, but have the behaviour defined within the object.
Sure this leads to coupling with a utility class, but to be fair not all couplings are bad, some are nesecarry to achieve an end goal, dont get bogged down by these things

Related

A faster way of doing objectToArray

Ive got this snippet of code below which works perfectly fine. I have been profiling it and the bit of code gets used alot of times, so I want to try figure out how to write it in a way that will perform better than the current way its written.
Is there a more efficient way to write this?
function objectToArray($d) {
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
// Return array converted to object Using __FUNCTION__ (Magic constant) for recursive call
return array_map(__FUNCTION__, $d);
}
else {
// Return array
return $d;
}
}
You could implement a toArray() method to the class that needs to be converted:
e.g.
class foo
{
protected $property1;
protected $property2;
public function __toArray()
{
return array(
'property1' => $this->property1,
'property2' => $this->property2
);
}
}
Having access to the protected properties and having the whole conversion encapsulated in the class is in my opinion the best way.
Update
One thing to note is that the get_object_vars() function will only return the publically accessible properties - Probably not what you are after.
If the above is too manual of a task the accurate way from outside the class would be to use PHP (SPL) built in ReflectionClass:
$values = array();
$reflectionClass = new \ReflectionClass($object);
foreach($reflectionClass->getProperties() as $property) {
$values[$property->getName()] = $property->getValue($object);
}
var_dump($values);
depends what kind of object it is, many standard php objects have methods built in to convert them
for example MySQLi results can be converted like this
$resultArray = $result->fetch_array(MYSQLI_ASSOC);
if its a custom class object you might consider implementing a method in that class for that purpose as AlexP sugested
Ended up going with:
function objectToArray($d) {
$d = (object) $d;
return $d;
}
function arrayToObject($d) {
$d = (array) $d;
return $d;
}
As AlexP said you can implement a method __toArray(). Alternatively to ReflexionClass (which is complex and expensive), making use of object iteration properties, you can iterate $this as follow
class Foo
{
protected $var1;
protected $var2;
public function __toArray()
{
$result = array();
foreach ($this as $key => $value) {
$result[$key] = $value;
}
return $result;
}
}
This will also iterate object attributes not defined in the class: E.g.
$foo = new Foo;
$foo->var3 = 'asdf';
var_dump($foo->__toArray());)
See example http://3v4l.org/OnVkf
This is the fastest way I have found to convert object to array. Works with Capsule as well.
function objectToArray ($object) {
return json_decode(json_encode($object, JSON_FORCE_OBJECT), true);
}

PHP object method doesn't behave as I expect

I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)

PHP Class Property Name

I have a class called contact:
class contacts
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
At some point in my code I would like to point to a property within that class and return the name of the property.
<input type="text"
id="<?php key($objContact->Name)" ?>"
name="<?php key($objContact->Name)" ?>"
value="<?php $_POST['contact'.key($objContact->Name)]" />
My issue being that the key() function only deals with arrays or objects. $objContact->Name itself does not meet these requirements. I know it would be just as simple to type the name itself out into the ID and NAME fields but this is for other code verification uses. Imagine the processor page:
$objContact = new contact();
$objContact->Email = $_POST[$objContact->Email->**GetSinglePropertyName()**];
$objContact->PhoneNumber = $_POST[$objContact->PhoneNumber->**GetSinglePropertyName()**];
This allows me to turn on STRICT and ensure that as I'm writing I'm not creating any fat finger errors along the way that are going to have me denting my head anymore than it presently exist.
UPDATE WITH ANSWER
Answer provided by: linepogl
Now I've taken linepogl's idea and extended is some so it can work very easily with my existing code base. Here's what I've come up with:
class baseData {
public $meta;
public function __construct() {
$this->meta = new Meta($this);
}
}
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key;
}
}
}
class contacts extends baseData
{
public $ID;
public $Name;
public $Email;
public $PhoneNumber;
public $CellPhone;
public $IsDealer;
public $DealerID;
}
Which means I can now call the following code with the desired results:
$objContact = new contacts();
echo($objContact->meta->Email);
So, you want when you type $objContact->Name to take as an answer not the evaluation of this expression but its meta data, which in this case is a ReflectionProperty object.
What you want is a feature that is called metaprogramming ( http://en.wikipedia.org/wiki/Metaprogramming ). Of course php does not support that but there are other languages that do, such as Lisp etc. Rumors say that C# 5.0 will introduce such features.
You can achieve a similar effect by using Reflection ( http://php.net/manual/en/book.reflection.php ). You can get the meta-object of $objContact (ReflectionClass) and iterate over the properties.
So, there is no way to identify a specific property with an identifier. The only way to do is is with a string of its name.
EDIT:
Yet, there a way to simulate it! Write a class like this:
class Meta {
public function __construct($obj) {
$a = get_object_vars($obj);
foreach ($a as $key => $value){
$this->$key = $key; // <-- this can be enhanced to store an
// object with a whole bunch of meta-data,
// but you get the idea.
}
}
}
So now you will be able to do this:
$meta = new Meta($objContact);
echo $meta->Name; // <-- with will return 'Name'!
You can use get_object_vars() like this:
$properties = get_object_vars($objContact);
foreach($properties as $name => $value)
{
if($value == $objContact->Name)
{
//here's youre name
}
}
but with this you will have to assume that $objContact->Name has unique value over all properties...
The key() function works very well with objects. It just doesn't accomplish what you are seemingly trying to do.
$c = new contacts;
end($c);
print key($c); // "DealerID"
You can foreach over object attributes, and PHP remembers the last accessed key(). But I'm not sure if this is what you want.
As alluded to by konforce, is this what you are looking for?
$var = 'Name';
$Obj->$var;//Obj's Name property
...
id="<?php $var ?>" //id="Name"
...
$_POST['contact'.$var];//$_POST['contactName']

json_encode on class with magic properties

I am trying to json_encode an array of objects who all have magic properties using __get and __set. json_encode completely ignores these, resulting in an array of empty objects (all the normal properties are private or protected).
So, imagine this class:
class Foo
{
public function __get($sProperty)
{
if ($sProperty == 'foo')
{
return 'bar!';
}
return null;
}
}
$object = new Foo();
echo $object->foo; // echoes "foo"
echo $object->bar; // warning
echo json_encode($object); // "{}"
I've tried implementing IteratorAggregate and Serializable for the class, but json_encode still doesn't see my magic properties. Since I am trying to encode an array of these objects, an AsJSON()-method on the class won't work either.
Update! It seems the question is easy to misunderstand. How can I tell json_encode which "magic properties" exist? IteratorAggregate didn't work.
BTW: The term from the PHP documentation is "dynamic entities". Whether or not the magic properties actually exist is arguing about semantics.
PHP 5.4 has an interface called JsonSerializable. It has one method, jsonSerialize which will return the data to be encoded. This problem would be easily fixed by implementing it.
json_encode() doesn't "asks" the object for any interface. It directly fetches the HashTable pointer that represents the properties of an object by calling obj->get_properties(). It then iterates (again directly, no interface such as Traversable, Iterator etc. is used) over this HashTable and processes the elements that are marked as public. see static void json_encode_array() in ext/json/json.c
That makes it impossible to have a property to show up in the result of json_encode() but not to be accessible as $obj->propname.
edit: I haven't tested it much and forget about "high performance" but you might want to start with
interface EncoderData {
public function getData();
}
function json_encode_ex_as_array(array $v) {
for($i=0; $i<count($v); $i++) {
if ( !isset($v[$i]) ) {
return false;
}
}
return true;
}
define('JSON_ENCODE_EX_SCALAR', 0);
define('JSON_ENCODE_EX_ARRAY', 1);
define('JSON_ENCODE_EX_OBJECT', 2);
define('JSON_ENCODE_EX_EncoderDataObject', 3);
function json_encode_ex($v) {
if ( is_object($v) ) {
$type = is_a($v, 'EncoderData') ? JSON_ENCODE_EX_EncoderDataObject : JSON_ENCODE_EX_OBJECT;
}
else if ( is_array($v) ) {
$type = json_encode_ex_as_array($v) ? JSON_ENCODE_EX_ARRAY : JSON_ENCODE_EX_OBJECT;
}
else {
$type = JSON_ENCODE_EX_SCALAR;
}
switch($type) {
case JSON_ENCODE_EX_ARRAY: // array [...]
foreach($v as $value) {
$rv[] = json_encode_ex($value);
}
$rv = '[' . join(',', $rv) . ']';
break;
case JSON_ENCODE_EX_OBJECT: // object { .... }
$rv = array();
foreach($v as $key=>$value) {
$rv[] = json_encode((string)$key) . ':' . json_encode_ex($value);
}
$rv = '{' . join(',', $rv) .'}';
break;
case JSON_ENCODE_EX_EncoderDataObject:
$rv = json_encode_ex($v->getData());
break;
default:
$rv = json_encode($v);
}
return $rv;
}
class Foo implements EncoderData {
protected $name;
protected $child;
public function __construct($name, $child) {
$this->name = $name;
$this->child = $child;
}
public function getData() {
return array('foo'=>'bar!', 'name'=>$this->name, 'child'=>$this->child);
}
}
$data = array();
for($i=0; $i<10; $i++) {
$root = null;
foreach( range('a','d') as $name ) {
$root = new Foo($name, $root);
}
$data[] = 'iteration '.$i;
$data[] = $root;
$root = new StdClass;
$root->i = $i;
$data[] = $root;
}
$json = json_encode_ex($data);
echo $json, "\n\n\n";
$data = json_decode($json);
var_dump($data);
There is at least one flaw: It doesn't handle recursion, e.g.
$obj = new StdClass;
$obj->x = new StdClass;
$obj->x->y = $obj;
echo json_encode($obj); // warning: recursion detected...
echo json_encode_ex($obj); // this one runs until it hits the memory limit
From your comment:
I am asking about the magic properties, not the methods. – Vegard Larsen 1 min ago
There is no such thing as a magic property.
All you have right now is a magic method that gets called when you try to access a non-visible property.
Let's say it again
$obj->foo does not exist
The way a magic method is implemented is not a concern of PHP, and it can't magically know that you are using your magic method to 'magically' make it look like there is $obj->foo.
If a property does not exist, it will not be put into the object when you json_encode it.
Furthermore, even if json_encode knew that __get was active, it wouldn't know what value to use to call it.
This is an incredibly old thread, but to not confuse other posters who are interested in how magic methods are used to get/set properties in PHP and how that affects JSON encoding, here is my understanding.
Including __get and __set methods in a class give you an interface to deal with dynamically named properties for a given class. Most people define an internal associative array that does the housekeeping.
The reason your foo/bar example doesn't show up in JSON encoding is because you are simply creating an association that returns a value. It's not setting a property in the object itself to that value.
If you did something like:
public function set($name, $value) {
$this->data[$name] = $value;
}
Then if you called :
$foo = new ObjectClass;
$foo->set('foo','bar');
now there is a element in that array $data['foo'] = 'bar'
if you json_encode the object, then that relationship will be represented.
json_encode does not encode methods, only properties. There's no way around it. For your code, the functional equivalent of your magic __get, would be to include in the constructor a call to set, that "hardwires" the value of the property named "foo".
Ultimately, I don't know what specifics you are wrestling with as you didn't provide much in the way of detail. However, json_encoding a object or an array will simply give you a list of properties that are available. If you have to pass through an interpreting function and are relying on that somehow, that's a different problem that I unfortunately have no answer for.
I hope this helps even though it is part of a downrated thread, which ironically, IMO, contains the solution.
I'd create a method on the object to return the internal array.
class Foo
{
private $prop = array();
public function __get($sProperty)
{
return $this->prop[$sProperty];
}
public function __set($sProperty, $value)
{
$this->prop[$sProperty] = $value;
}
public function getJson(){
return json_encode($this->prop);
}
}
$f = new Foo();
$f->foo = 'bar';
$json = $f->getJson();
This is the correct behavior
JSON is only able to contain data not methods - it is meant to be language independent so encoding object methods would not make sense.
How could it know your properties?
$object = new Foo();
echo $object->foo; // how do you know to access foo and not oof?
// how do you expect json_encode to know to access foo?
magic methods are syntactic sugar, and mostly fire back when you use them. this is one such case.
echo json_encode($object); // "{}"
of course it's empty, $object has zero public properties, just a magic method and the ensuing syntactic sugar (turned sour)
i have found the following that worked for me creating classes with dynamic properties and outputing them with json_encode. Maybe it helps other people to.
http://krisjordan.com/dynamic-properties-in-php-with-stdclass

Listing all objects of a certain class

Ok my problem is as follows;
I have a class that describes a pet with this constructor;
public function __construct($name, $type, $age)
So what I want to do is make a number of pet objects, then I want to print all the attributes of all the objects of this class so that it looks something like this
What is the best way of going about it? I know how to iterate through an object's variables, but my main concern is how to iterate through all objects of a certain class. I would love it if someone could show me a code example of something, particularly if there is a way to do it without the use of arrays.
Any help is appreciated!
You could, in the class constructor, append $this to a static array that keeps all the elements of this type:
class Pet {
public static $allPets = array();
function __construct($name, $type, $age) {
self::$allPets[] = $this;
// more construction
}
}
Your list of all Pet objects is now in Pet::$allPets.
Normally you would expect to have some way of tracking the instances you've created, maybe in an array or some kind of containing class.
But for the sake of argument, you could check all the variables in the current scope with get_defined_vars(), recursively searching any arrays or objects you find, with something like this:
function findInstancesOf($classname, $vars)
{
foreach($vars as $name=>$var)
{
if (is_a($var, classname))
{
//dump it here
echo "$name is a $classname<br>";
}
elseif(is_array($var))
{
//recursively search array
findInstancesOf($classname, $var);
}
elseif(is_object($var))
{
//recursively search object members
$members=get_object_var($var);
findInstancesOf($classname, $members);
}
}
}
$vars = get_defined_vars();
findInstancesOf('MyPetClass', $vars);
I guess it depends on your structure, but I´d have another object / class that contains all generated pet objects, so I would loop through that.
Well, you could make a custom create option and use static variables to store an instance of each created class
Class Pet
{
public static $pets = array();
public static create($name, $type, $age)
{
$pet = new Pet($name, $type, $age);
self::$pets[] = $pet;
return $pet;
}
}
Pet::createPet("test", "test", 42);
Pet::createPet("test", "test", 42);
Pet::createPet("test", "test", 42);
foreach(Pet::$pets as $pet)
{
echo $pet->name;
}
i would make a foreach loop
foreach($myobject as $key => $pent)
{
echo $key;
echo $pent;
}

Categories