How to create array-like data-structures with object keys in PHP? - php

I want create arrays with object keys in PHP, i.e. something like this:
<?php
$keyObject = new KeyObject;
$valueObject = new ValueObject;
$hash = array($keyObject => $valueObject);
However, this raises an error. Arrays may only have integer or string keys. I end up having to do something like:
$hash = array(
'key' => $keyObject,
'value' => $valueObject);
This works but it's not as neat as I'd like. Is there a better way? (Perhaps something from the SPL that I'm missing...)
TIA

You can use SplObjectStorage from the SPL as a map with object keys:
$map = new SplObjectStorage;
$key = new StdClass;
$value = new StdClass;
$map[$key] = $value;

Related

Why is variable not changing in a PHP array of objects?

I am trying to assemble an array of objects from a variety of sources in PHP (I'm new to the language). The problem is that I am not able to store the data within the $bandwidthData array in the foreach loop I am trying to write.
private function _getData($startDay, $totalDays)
{
$devices = ubntDevices::getDevices();
$data = [];
$bandwidthData = [];
$count = 0;
foreach ($devices as $device) {
$bandwidthData[$count]['device'] = $device;
$bandwidthData[$count]['bandwidth'] = new ubntModel($device->file);
$bandwidthData[$count]['bandwidth']->getMonthData();
$bandwidthData[$count]['tree'] = new graphTree($device->hostid);
$bandwidthData[$count]['graphid'] = ubntGraph::getGraphByHostId($device->hostid);
$bandwidthData[$count]['hostname'] = $device->host_name;
$count++;
}
return $bandwidthData;
}
If I return from within the foreach loop, I get the correct output (but obviously for only the first device). I have tested all of the other function sources, and they seem to be returning the right data. Any idea what I could be doing wrong? Thank you in advance.
Your PHP error log should indicate what's going wrong. XDebug is very highly recommended as well.
However, nowadays it is more common to use an associative array like this:
private function _getData($startDay, $totalDays)
{
$devices = ubntDevices::getDevices();
$bandwidthData = [];
foreach ($devices as $device) {
$ubntModel = new ubntModel($device->file);
$deviceData = array('device' => $device,
'ubntModel' => $ubntModel,
'bandwidth' => $ubntModel->getMonthData(),
'tree' => new graphTree($device->hostid),
'graphid' => ubntGraph::getGraphByHostId($device->hostid),
'hostname' => $device->host_name);
$bandwidthData[] = $deviceData;
}
return $bandwidthData;
}
Some things I'm seeing:
Is this variable in use?
$data = [];
Also, this assignment runs but is a discouraged approach because at this point $bandwidthData[$count] does not exist:1
$bandwidthData[$count]['device'] = $device;
That can be converted to:
$bandwidthData[$count] = [ 'device' => $device ];
Also, this just a getter returning nowhere. Isn't it?
$bandwidthData[$count]['bandwidth']->getMonthData();
Also to further learn PHP I can suggest such cleaner approach for that code snippet, just to improve readability:
private function _getData( $startDay, $totalDays ) {
$bandwidthData = [];
foreach ( ubntDevices::getDevices() as $device ) {
$bandwidthData[] = [
'device' => $device,
'bandwidth' => new ubntModel( $device->file ),
'tree' => new graphTree( $device->hostid ),
'graphid' => ubntGraph::getGraphByHostId( $device->hostid ),
'hostname' => $device->host_name,
];
}
return $bandwidthData;
}
Anyway you have to learn how to debug that simple small block of code just looking at your server logs, or with a lazy var_dump( $bandwidthData[ $count ] ) in your suspected line (do not fight about this debugging approach: it's super stupid, but dramatically simple and effective, and friendly for newcomers - if you have not the possibility to setup a debugger because maybe the server is not yours etc.) or setting up a debugger.
1 from https://www.php.net/manual/en/language.types.array
If $arr doesn't exist yet, it will be created, so this is also an alternative way to create an array. This practice is however discouraged because if $arr already contains some value (e.g. string from request variable) then this value will stay in the place and [] may actually stand for string access operator. It is always better to initialize a variable by a direct assignment

In PHP, how can I create and add to an object?

Just so you know I'm working in WordPress. I have an array and want to create an object with only certain values from that array.
Then I have another separate array, I'd like to add to this new object. I might be over complicating things. If I am, please let me know.
Here's what I have so far:
$custom = get_post_custom(); //Gets array of values
$picObject = (object)$custom; //Creates object
$picCount = $custom['picturecount'][0];
for ($x = 1; $x <= $picCount; $x++) {
// This assembles a URL that I want to add to the array.
$finalUrl = $picUrl.$gsi.'&picfilename='.$vin.'_00'.$x.'.jpg';
}
Let me know if you need anything else. Thanks in advance everyone!
If you want to create an object with only some values from your array, you shouldn't cast the array because you'll end up with all of its values. Instead, create a new object and set the values you want:
$array = array(
'foo' => 'bar',
'bar' => 'baz'
);
$object = new stdClass();
$object->bar = $array['bar'];
$object->something_else = 'w00t!';
Casting an array to object (i.e. (object)$array) will get you the same type of object, so you can still use $object->new_property = 'foo'; to add stuff to it.

Using foreach loop through array in an array using php

I am fairly new to PHP and have been working on looping through this array for days...sigh...
http://pastebin.com/Rs6P4e4y
I am trying to get the name and headshot values of the writers and directors array.
I've been trying to figure out the foreach function to use with it, but have had no luck.
<?php foreach ($directors as $key => $value){
//print_r($value);
}
?>
Any help is appreciated.
You looking for some such beast? You didn't write how you wanted to process them, but hopefully this helps you.
$directors = array();
foreach( $object->people->directors as $o )
$directors[] = array( 'name' => $o->name, 'headshot' => $o->images->headshot );
$writers = array();
foreach( $object->people->writers as $o )
$writers[] = array( 'name' => $o->name, 'headshot' => $o->images->headshot );
var_dump( $directors );
var_dump( $writers );
Last note, if there's no guarantee that these members are set, you use isset before any dirty work.
Hope this helps.
Use -> to access properties of the objects.
foreach ($directors as $director) {
echo 'Name: ' . $director->name . "\n";
echo "Headshot: " . $director->images->headshot . "\n";
}
Your solution has already been posted, but I want to add something:
This isn't an Array, it's an object. Actually the directors property of the object is an Array. Look up what an object is and what associative arrays are!
Objects have properties, arrays have keys and values.
$object = new stdClass();
$object->something = 'this is an object property';
$array = new array();
$array['something'] = 'this is an array key named something';
$object->arrayproperty = $array;
echo $object->arrayproperty['something']; //this is an array key named something
Good luck with learning PHP! :)
Having variable $foo, which is an object, you can access property bar using syntax:
$foo->bar
So if you have an array od directors named $directors, you can simply use it the same way in foreach:
foreach ($directors as $value){
echo $value->name." ".$value->images->headshot;
}

Creating an array of objects in PHP

I would like to know what is the right of creating objects arrays in php.
My goal here is to be able to get data like this:
$obj = new MyClass();
echo $obj[0]->parameter; //value1
echo $obj[1]->parameter; //value2
Thanks for your time.
EDIT:
And if I want to do it in class it should look like this?
class MyClass{
public $property;
public function __construct() {
$this->property[] = new ProjectsList();
}
}
Any of the following are valid:
$myArray = array();
$myArray[] = new Object();
$myArray[1] = new Object();
array_push($myArray, new Object);
Try this,
$obj = array(new stdClass(), new stdClass())
or
$obj = array()
$obj[] = new stdClass()
$obj[] = new stdClass()
EDIT:
Class to stdClass
An important hint ...
The memory allocation for PHP arrays is exponential. A simple example: All array entries fit into an array, that allocates 2MB of memory. If this memory is no longer sufficient for all array entries, the memory allocation is expanded exponentially until the PHP memory limit is reached. If the array needs more than the 2 MB in this example, it will expand to 4MB, 16MB, etc.
When dealing with objects, better use collections. PHP provides the SplObjectStorage. This kind of collection allocates the exactly needed memory for its contents. Iteration over this collections behaves like using a yield. Only the memory for the current object in iteration is allocated. Beside that the SplObjectStorage class takes objects only. Should work perfectly for your purposes.
<?php
declare('strict_types=1');
namespace Marcel;
$collection = new SplObjectStorage();
$object1 = new stdClass();
$object2 = new stdClass();
$collection->attach($object1);
$collection->attach($object2);
The above shown code allows some stricter searching.
$collection->contains($object1); // returns true
Detaching an item works like a charme.
$collection->detach($object1);
$collection->contains($object1); // returns false
Iterations works with a pretty fast foreach loop or a while loop.
$collection->rewind();
foreach ($collection as $object) {
// yielding works here
}
$collection->rewind();
while ($collection->valid()) {
// yielding also works here automatically
$collection->next();
}
hope this will be helpful
$newArray[] = (object) array();
Honestly, I think you are on the right path. from what it sounds like you are not just trying to add to arrays, but convert arrays to objects.
<?php
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'
?>
PHP Objects
EDIT: I don't think you could add an object like this:
$this->property[] = new ProjectsList();
the "new ProjectsList()" would be how you would create an object from a class. ProjectsList would need to be a class. it would look more like this:
$obj = new ProjectsList;
$this->property[] = $obj;
you would need to make sure the ProjectsList existed first though.

can i use stdClass like an array?

is it possible to make stdClass objects work like a generically indexed array?
i.e.
$array = Array
(
[0] => 120
[1] => 382
[2] => 552
[3] => 595
[4] => 616
)
would be constructed like
$a = array();
$array[] = 120;
$array[] = 382;
etc.
but if i do that with an object it just overwrites itself:
$obj = new stdClass;
$obj->a = 120;
$obj->a = 382;
i know i can change 'a' every time,
sorry if this is a stupid question but it's stumping me for some reason!
Appreciate any help :)
Dan
In short, no, because you will always have to name your properties. Going through the trouble of writing a simple class with ArrayAccess makes no sense either as you've essentially recreated an array with nothing to show for it except extreme sacrifices in performance and transparency.
Is there some reason your problem cannot be solved infinitely more simply by using an array, or is this just a wish-I-knew question?
EDIT: Check out this question for more info.
No, you can't. Using the brackets ([]) like that is called "ArrayAccess" in PHP, and is not implemented on the stdClass object.
It sounds like you might want something like
$foo = new stdClass();
$foo->items = array();
$foo->items[] = 'abc';
$foo->items[] = '123';
$foo->items[] = 'you and me';
You could also try casting an array as a stdClass to see what happens.
$foo = array();
$foo[] = 'abc';
$foo[] = '123';
$foo[] = 'you and me';
$foo = (object) $foo;
var_dump($foo);
I can't really see what you mean to do, short of
<?php
$obj->a = array();
$obj->a[] = 120;
$obj->a[] = 382;
// ...
?>
You cannot simply "push" a field onto an object. You need to know the name of the field in order to retrieve the value anyways, so it's pretty much nonsense.
An object is not an array. If you want numerically indexed elements, use an array.
If you want named elements use either an Object or an Associative Array.
As for why you're getting different behaviour, it's because in the Array, you are not specifying an index, so PHP uses the length of the Array as the index. With the Object, you have to specify the name (in this case 'a').
The other thing you may want to do is have an Object, with a member that is an array:
$obj = new stdClass;
$obj->arr = array();
$obj->arr[] = 'foo';
$obj->arr[] = 'bar';
also don't forget you can cast an array to an object:
$obj = (object) array(
'arr' => array(
'foo',
'bar'
)
);
Only for the sake of OOP, don't use classes. If you really want to implement this functionality, use this class:
class ArrayClass
{
protected $storage = array();
public function push($content) {
$this->storage[] = $content;
return $this;
}
public function get($index) {
if (isset($this->storage[$index])) {
return $this->storage[$index];
} else {
//throw an error or
return false;
}
}
}
You can get exactly this in JavaScript.

Categories