PHP Object () identifier - php

What is the name of the integer between brackets in a var_dump of an object. And how do I acces it with PHP?
I'm referring to the (3) in the next example.
object(SimpleXMLElement)#18 (3) {
["ID"]=>
string(3) "xx"
["Name"]=>
string(25) "xx"
["Date"]=>
string(10) "xx"
}

this is the number of properties of an object. to count this, you can cast your object to an array and use count():
$number = count((array)$object);
EDIT: i did a small test (see at codepad) wich prooves that casting to an array is what you want to do instead of using get_object_vars() as others mentioned because the later one doesn't count private properties while array-casting as well as var_dump do count these.

It's the number of public properties of that object, and isn't directly accessible

What is the name of the integer between brackets in a var_dump of an object. And how do I acces it with PHP?
I'm referring to the (3) in the next example.
That's the number of public members it has (namely, ID, Name and Date). If you want to know that number, you could just use count( get_object_vars( $object ) ):
<?php
$foo = new stdClass;
$foo->foo = 42;
$foo->bar = 42;
$foo->baz = 42;
var_dump( count( get_object_vars( $foo ) ) );

Related

PHP Array to Object

Given the following array:
$array = array(
'item_1' => array(
'item_1_1' => array(
'item_1_1_1' => 'Hello',
),
'item_1_2' => 'World',
),
'item_2' => array(),
);
How can I convert that into an Object?
Option 1
$obj = (object) $array;
Or
Option 2
$object = json_decode(json_encode($array), FALSE);
Or something else?
I would like to know the difference in the output between the 2 option and understand the best practice for creating this conversion.
Well you are answering somehow your own question, but if you want to have an object with the attributes like your array you have to cast it, this way an array will remain an array
$obj = (object) $array;
OUTPUT:
object(stdClass)#1 (2) {
["item_1"]=>
array(2) {
["item_1_1"]=>
array(1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
if you are using the json_decode version it will convert arrays to objects too:
object(stdClass)#2 (2) {
["item_1"]=>
object(stdClass)#3 (2) {
["item_1_1"]=>
object(stdClass)#4 (1) {
["item_1_1_1"]=>
string(5) "Hello"
}
["item_1_2"]=>
string(5) "World"
}
["item_2"]=>
array(0) {
}
}
NOTE: just the empty array will be an array here.
To Answer your question: The best practice depends on what YOU need.
It depends, really: if you are working on data that might be an array in one case, and an object the next, it would probably be best to use the json_decode trick, simply because unlike a cast, its result is "recursive". There is one very important thing to keep in mind here, though: numeric indexes can, and probably will cause problems for you at some point in time. Take a look at this bug report
This is documented here, but not in a way that really stands out:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible;
Exampe of the problem:
$data = [
'foo' => 'bar',
123 => 'all is well',
];
$obj = json_decode(json_encode($data));
var_dump($obj->foo);//bar
var_dump($obj->{123});//all is well
$cast = (array) $obj;
var_dump($cast);//shows both keys
var_dump(isset($cast[123]));//FALSE!!!
var_dump(isset($cast['123']));//FALSE
Basically: If you start converting arrays to objects and back again, numeric keys are not reliable anymore. If I were you, I'd simply change the code that is passing the data where possible, or I'd create a value object that can be set using an array or an object, and normalize the data that way.

Understanding CodeIgniter objects and multidimensional arrays

I'm working on a project in CodeIgniter 2 and now I'm stuck on the most basic of concepts.
Model:
Get an object array from my table which contains all rows that match a specific value for a field named foo. There can be one or more rows that match. In this example, two rows.
public function get_sample($foo)
{
$query = $this->db->get_where('sample_db', array('foo' => $foo));
return $query->result();
}
Controller:
Assign the results and make output available to view.
public function view($foo)
{
$data['array'] = $this->sample_model->get_sample($foo);
$this->load->view('view', $data);
}
View:
echo var_dump($array); // for testing
echo $array[1]->text
var_dump() of $array:
array(2) {
[0]=> object(stdClass)#23 (4) {
["id"]=> string(1) "1"
["foo"]=> string(3) "bar"
["number"]=> string(4) "1234"
["text"]=> string(23) "This is content in 1234"
}
[1]=> object(stdClass)#24 (4) {
["id"]=> string(1) "2"
["foo"]=> string(3) "bar"
["number"]=> string(4) "9999"
["text"]=> string(23) "This is content in 9999"
}
}
The rendered ouput of echo $array[1]->text; is: This is content in 9999
And I understand how all that is working: $array[1]->text is the content of the text field in the array object with the index of 1, my second object.
However, I have a field called number and I want to access the object with a certain number and get its corresponding text value.
Example: How can I retrieve the value of text where the number is 9999? I cannot use $array[1]->text since I can never be sure of the object's position in the array. Something like $array['number' => '9999']->text, but I know that's not right. Maybe I need to loop through the array looking for a match?
This looks so simple yet everything I've tried has failed and resulted in various PHP errors. I've been studying the PHP manual here and here, but cannot seem to find anything about what I'm looking to do, or maybe I'm just misapplying what I'm reading. Any guidance is appreciated.
In addition to an answer using best practices following the MVC model, I'm hoping for a link to the proper page in the documentation, as well as pointing out any errors in my wording/terminology above.
EDIT:
This answer contains the actual code I used to solve my problem. Although, Yagi's answer was accepted because it put me in the right direction.
How about using this :
foreach ($array as $row) {
if ($row->number == '9999') {
echo $row->text;
}
}
Loop through the array, and find the number object value of 9999 and get the text
Why don't you just to a query and search for that number (or order by that number?)
Either way, what you need is a multidimensional array search function (that iterates through array of object and returns the found field value combo )
Something like this (put this in helper)
function multi_array_search($array, $field, $value)
{
$results = array();
if (is_array($array))
{
if ($array->$field == $value) //chek the filed against teh value, you can do addional check s(i.e. if field has been set)
$results[] = $array;
foreach ($array as $subarray)
$results = array_merge($results, multi_array_search($subarray, $key, $value)); //recurisve serach
}
return $results;
}
//than in view or in controller, depending where you need it
$result = multi_array_search($array, "number", "9999");
var_dump($result) will return or whether number of foudn instances
array() {
[0]=> object(stdClass)#24 (4) {
["id"]=> string(1) "2"
["foo"]=> string(3) "bar"
["number"]=> string(4) "9999"
["text"]=> string(23) "This is content in 9999"
}
}
you might be looking for something like this...
array_filter($array, function($o){ return $o->number == 9999; } );
http://php.net/manual/en/function.array-filter.php
EDIT
$o is the parameter in the callback function. each element of the array is passed to the callback function. if the function returns false, the element will be filtered out.
$arr = array(
(object) array(
'num' => 33,
'text' => 'hello',
),
(object) array(
'num' => 44,
'text' => 'world',
),
);
$filtered = array_filter($arr, function($o){ return $o->num == 33; });
echo $filtered[0]->text; // hello
as you stated, index will remain, so use array_values or array_shift. here's an example with function
function get_by_num($arr, $num){
return array_shift(array_filter($arr, function($o) use ($num) { return $o->num == $num; }));
}
$obj = get_by_num($arr, 44);
var_dump($obj);
// object(stdClass)#2 (2) { ["num"]=> int(44) ["text"]=> string(5) "world" }
in this case $obj will be either NULL if element is not found, or the first match. $num is transferred along so you can use any value. you can even improve it:
function get_first_match($arr, $field, $val){
return array_shift(array_filter($arr, function($o) use ($field, $val) { return $o->{$field} == $val; }));
}
$obj = get_first_match($arr, 'num', 44);
and now you can search any field. in your case
$obj = get_first_match($array, 'number', 9999);
Thanks to Yagi's answer, I came up with the following very simple solution. I loop through the array and assign the value of text to a new array with an index that matches the value of number. Then in the view file, I can access the text value based on this index.
Controller:
public function view($foo)
{
$data['array'] = $this->sample_model->get_sample($foo);
foreach ($data['array'] as $row) {
$data['result'][$row->number] = $row->text;
};
$this->load->view('view', $data);
}
View:
if (isset($result[9999])) echo $result[9999];

PHP - Access value from previously-defined key during array initialization

I'm looking to see if it's possible to access the value of a key I previously defined within the same array.
Something like:
$test = array(
'foo' => 1,
'bar' => $test['foo']
);
I know I can always do so after initialization, I am just wondering if it's possible during initialization?
No, $test doesn't exist until the full constructor is evaluated.
For example: http://codepad.viper-7.com/naUprJ
Notice: Undefined variable: test..
array(2) { ["foo"]=> int(1) ["bar"]=> NULL }
It's probably for the best. Imagine of this worked:
$test = array('foo' => $test['foo']); // mwahaha
If you need to do this a lot, you could create a class that takes keys of a particular format that flag to the class constructor that it should be parsed until all relevant keys are evaluated.

Object extract properties

I have an object as this:
object(stdClass)#27 (1)
{
[0] => object(stdClass)#26 (6)
{
["_id"] => object(MongoId)#24 (1)
{
["$id"] => string(24) "4e6ea439caa47c2c0c000000"
}
["username"] => string(16) "wdfkewkghbrjkghb"
["email"]=> string(24) "wdhbfjkwhegerg#€rg.efg"
["password"]=> string(32) "4297f44b13955235245b2497399d7a93"
["slug"]=> string(16) "wdfkewkghbrjkghb"
["insert_datetime"]=> string(19) "2011-09-13 12:09:49"
}
}
I assign this object to $user.
I can't get access on this object properties doing $user->username cause I receive the message:
Undefined property: stdClass::$username
Then if I do var_dump(get_object_vars($user)) it returns an empty array.
How do I grab the properties? I don't want to use loops if I can avoid it.
The process is this:
Retrieve results from mongo_db:
$returns = array();
while ($documents->hasNext())
{
if ($this->CI->config->item('mongo_return') == 'object')
{
$returns[] = (object) $documents->getNext();
}
if ($this->CI->config->item('mongo_return') == 'array')
{
$returns[] = (array) $documents->getNext();
}
}
if ($this->CI->config->item('mongo_return') == 'object')
{
return (object)$returns;
}
if ($this->CI->config->item('mongo_return') == 'array')
{
return $returns;
}
passing data to model
function populateBy($what = false) {
return $this->mongo_db
->where($what)
->get($this->tb['users']);
}
definitely grab results in controller:
$what = array(
'email'=>$email,
'password'=>$password,
'confirm'=>'1'
);
$user = $this->model_user->populateBy($what);
As gilden says, the property you're looking for is a property of a subobject. However, he missed that object property access is not the same as array element access.
The real problem you're facing here is that you've converted an array to object, and now you have a numeric property name. To get to properties you have to use syntax like $user->0->username, but clearly this is not valid as 0 is not a valid variable name.
From the documentation:
If an object is converted to an array, the result is an array whose
elements are the object's properties. The keys are the member variable
names, with a few notable exceptions: integer properties are
unaccessible [sic]; private variables have the class name prepended to the
variable name; protected variables have a '*' prepended to the
variable name. These prepended values have null bytes on either side.
This can result in some unexpected behaviour:
The function get_object_vars converts back into an array again so that it appears to work, but in fact anything could happen: the behaviour is unspecified because the object elements were rendered inaccessible in the intermediate stage. Similarly, $user->{'0'}->username may work for you but I would avoid it.
Unfortunately this means that you'll have to change the way your code works: do not convert a numerically-indexed array to an object.
Your username property is not where you're looking for it. Try
$username = $user[0]->username;
EDIT Trying this gives me some unexpected results. I get "Cannot use object of type stdClass as array" so what I think you should do is using a foreach loop
// $users is the object in this sample
foreach($users as $user)
{
$username = $user->username;
}
EDIT 2 You could use get_object_vars
$users = get_object_vars($users);
$username = $users[0]->username;

Question about var_dump output

When I var_dump an object, the output looks like this:
object(XCTemplate)#2477 (4) {
["id"]=>
string(1) "1"
["attributes"]=>
array(0) {
}
["db_table_name"]=>
string(14) "template_names"
["cache"]=>
array(0) {
}
}
XCTemplate is its class, of course, but what does the integer (here: 2477) after the # mean?
It's a unique id associated with that particular instance of XCTemplate. AFAIK this is not documented, and also there is no way to get it (other than using var_dump()); and I've looked at the Reflection class.
From what I've seen:
The ids are unique to every instantiation; starting at 1 and incrementing by 1 with every new object. This includes every object; they don't have to be of the same class.
Destroying an instance (eg: through unset) frees up its id and the next instantiated object can (and will) use it.
It's not related to the variable; eg:
$foo = new Foo();
var_dump($foo);
$foo = new Foo();
var_dump($foo);
Will produce different id's for different instantiations.
This is not the same as resource ids, where you can just convert to int to get the id:
$resource= curl_init();
var_dump($resource); // resource #1 of type curl
print(intval($resource)); // 1
print((int) $resource); // 1

Categories