php intersection of array of slightly different objects - php

I'm kind of new to programming and want to know if there is a short way to find the intersection of two arrays containing slightly different Objects. That's what I tried to use:
array_uintersect()
The Object are looking like this:
class object1
{
private $_customerId;
private $_orderId;
private $_someOtherStuff;
}
and:
class object2
{
private $_customerId;
private $_orderId;
private $_someDifferentStuff;
}
The custom function looking like this:
private function compareObjects($o1, $o2)
{
return $o1->compareObjectIntersection($o2);;
}
Using this method:
public function compareObjectIntersection($object)
{
if($this->_customerId < $object->getCustomerId() || $this->_orderId < $object->getOrderId())
{
return -1;
}
elseif$this->_customerId > $object->getCustomerId() || $this->_orderId > $object->getOrderId())
{
return 1;
}
return 0;
}
Is this possible without coding everything by myself with a lot of for-loops?
EDIT:
The idea was to get rid of all objects not containing the same pair of these two attributes:
private $_customerId;
private $_orderId;
In the first place i get an empty array as a result

You are not looking for the same objects as you have different types here, namely object1 and object2.
Instead you're looking for similiar objects in which you're looking for those which are same for customer-ID and order-ID.
This is important to note, as by only that you can say that the comparison does not belong into any of these two types, because you could place the comparison into both, object1 and object2.
In such a case where you can not clearly identify to which object type a functionality belongs to, a good rule of thumb is to place it between these objects, e.g. create a function or a new type of it's own for the operation itself.
That for a design decision.
Now about how to make such comparison of different objects easy? One way to do that is with a hash function.
Assuming that these two IDs are integers, you can create a hash for each of these different objects with a hash function:
function customer_order_hash($object) {
return sprintf('%d/%d', $object->getCustomerId(), $object->getOrderId());
}
This hash now makes it easy to identify objects that are the same or not: The hash will be the same.
You then can make use of it, e.g. getting all objects from $array1 that have corresponding objects in $array2:
function compare_objects($a, $b) {
return strcmp(customer_order_hash($a), customer_order_hash($b));
}
$result = array_uintersect($array1, $array2, 'compare_objects');
The result then contains only these objects from the first array that were found as well by such a comparison within the second array.
As you can see, there is no (written) loop at all. Just one hash function and one comparison function making use of it.
An object hash function normally works well for such comparisons (same or not). It can also work for sorting, however this example is not working for sorting.
Additional info: A built-in object hash function in PHP is spl_object_hash.

Related

php - multi-dimensional array wrapper class

I have some data represented as multi-dimensional arrays. I would like to embed these data into my OO application and provide extra functionality to these data but also a way to access it both with the traditional random access and using an iterator (so I could use foreach). In other words I would like to implement a wrapping class for a multi-dimensional array.
What I already tried:
I. ArrayAccess
The problem with this one is that the server uses PHP 5.2.17 and &offsetGet() gives an error, thus I can't return by reference, which means I can't implement multidimensional element access:
$obj[$key1][$key2] = $value;
Note, that upgrading to a newer PHP version is currently not an option
II. Using magic methods
This is a bit trickier, but my problems rose when I tried using a variable as key. E.g.
$obj->$key1[$key2] = $value;
The interpreter first evaluated $key1[$key2] throwing a notice and returning the first char of $key1, and uses that as key on my array. I don't know how to solve this one either. I thought of using brackets to force operation priority, but that had the same problem as in my next attempt:
III. Using simple get and set functions
Again, old PHP. It cries when I try to write:
$obj->get($key1)[$key2] = $value;
Because it doesn't know how to index an expression ending in round brackets.
There's still the lost resort option: make the array public and forget OO all together. But before I go there I want to be certain that there's just really no other way of doing this.
Sometimes, it's best shown with an example. For instance, you could have a multidimensional array with ordered quantities of a product, where the first index defines a customer, the second an order and the third the products. The value then is the quantity.
IV. Using simple get and set functions, but with multiple parameters:
$value = $obj->get($key1, $key2);
$obj->set($key1, $key2, $value);
or
$quantity = $orderedQuantities($customerName, $orderNo, $productCode);
The essence of writing an object wrapper, is that it looks like an object and behaves like such. If you implement it so that it looks and behaves like an array, you may just as well use an array. The only reason to wrap an array in an object that behaves like an array is that you can pass it around by reference, without using & parameters.
If that is your goal, just assign the array to $obj, and use $obj->arrayprop[$key1][$key2]. If on the other hand you want it to behave like an object, skip the array syntax altogether.
V. Using nested objects
So using the same example, you can write a customers object (kind of a collection), which embeds order objects, etc..
$quantity = $customers->getCustomerByName($customerName)->getOrder($orderNo)->getProduct($productCode)->quantity;
or, to make it more readable:
$customer = $customers->getCustomerByName($customerName);
$order = $customer->getOrder($orderNo);
$orderLine= $order->getOrderLine($productCode);
$quantity = $product->quantity;
Now, each of these entities are represented by an object. The advantage is that you can easily extend this structure with extra properties. You can give the customer collection 'findByCustomerNo' and 'findByName' methods to find a specific customer, but also a 'filterByPostalCode', which could return a new collection containing only the customers from that postal code.
$order could now contain functions to calculate totals.
$orderLine may contain only a productCode (key) and a quantity, but by making it an object, you can easily add discount, a customized name or description or other properties.
All in all, this structure allows a lot of flexibility, although it needs a little more typing at first and a little getting used to.
Using nested objects can make ArrayAccess work, without passing references. But you can forget about built in array functions completely.
<?php
class ArrObj implements ArrayAccess {
private $arr;
public function __construct($arr = null) {
$this->arr = $arr;
}
public function offsetExists($key) {
return isset($this->arr[$key]);
}
public function offsetGet($key) {
return $this->arr[$key];
}
public function offsetSet($key, $val) {
return $this->arr[$key] = $val;
}
public function offsetUnset($key) {
unset($this->arr[$key]);
}
}
$a = new ArrObj(array(
'foo' => new ArrObj(array(
'bar' => 'qwe'
))
));
echo $a['foo']['bar'] . '<br />';
$a['foo']['bar'] = 'asd';
echo $a['foo']['bar'] . '<br />';
?>
Outputs:
qwe
asd

Difference between ArrayIterator, ArrayObject and Array in PHP

Can somebody explain clearly the fundamental differences between ArrayIterator, ArrayObject and Array in PHP in terms of functionality and operation? Thanks!
Array is a native php type. You can create one using the php language construct array(), or as of php 5.4 onwards []
ArrayObject is an object that work exactly like arrays. These can be created using new keyword
ArrayIterator is like ArrayObject but it can iterate on itself. Also created using new
Comparing Array vs (ArrayObject/ArrayIterator)
They both can be used using the php's array syntax, for eg.
$array[] = 'foo';
$object[] = 'foo';
// adds new element with the expected numeric key
$array['bar'] = 'foo';
$object['bar'] = 'foo';
// adds new element with the key "bar"
foreach($array as $value);
foreach($object as $value);
// iterating over the elements
However, they are still objects vs arrays, so you would notice the differences in
is_array($array); // true
is_array($object); // false
is_object($array); // false
is_object($object); // true
Most of the php array functions expect arrays, so using objects there would throw errors. There are many such functions. For eg.
sort($array); // works as expected
sort($object); // Warning: sort() expects parameter 1 to be array, object given in ......
Finally, objects can do what you would expect from a stdClass object, i.e. accessing public properties using the object syntax
$object->foo = 'bar'; // works
$array->foo = 'bar'; // Warning: Attempt to assign property of non-object in ....
Arrays (being the native type) are much faster than objects. On the other side, the ArrayObject & ArrayIterator classes have certain methods defined that you can use, while there is no such thing for arrays
Comparing ArrayObject vs ArrayIterator
The main difference between these 2 is in the methods the classes have.
The ArrayIterator implements Iterator interface which gives it methods related to iteration/looping over the elements. ArrayObject has a method called exchangeArray that swaps it's internal array with another one. Implementing a similar thing in ArrayIterator would mean either creating a new object or looping through the keys & unseting all of them one by one & then setting the elements from new array one-by-one.
Next, since the ArrayObject cannot be iterated, when you use it in foreach it creates an ArrayIterator object internally(same as arrays). This means php creates a copy of the original data & there are now 2 objects with same contents. This will prove to be inefficient for large arrays. However, you can specify which class to use for iterator, so you can have custom iterators in your code.
ArrayObject and array are somewhat alike. Merely a collection of objects (or native types). They have some different methods that you can call, but it mostly boils down to the same thing.
However, an Iterator is something else completely. The iterator design pattern is a way to secure your array (making it only readable). Lets take the next example:
You have a class that has an array. You can add items to that array by using addSomethingToMyArray. Note however, that we do something to item before we actually add it to the array. This could be anything, but lets for a moment act like it is very important that this method is fired for EVERY item that we want to add to the array.
class A
{
private $myArray;
public function returnMyArray()
{
return $this->myArray;
}
public function addSomethingToMyArray( $item )
{
$this->doSomethingToItem( $item );
array_push( $item );
}
}
The problem with this, is that you pass the array by reference here. That means that classes that actually use returnMyArray get the real myArray object. That means that classes other than A can add things to that array, and therefor also change the array inside A without having to use the addSOmethingToMyArray. But we needed to doSOmethingToItem, remember? This is an example of a class not in control of its own inner status.
The solution to this is an iterator. Instead of passing the array, we pass the array to a new object, that can only READ things from the array. The most simple Iterator ever is something like this:
<?php
class MyIterator{
private $array;
private $index;
public function __construct( $array )
{
$this->array = $array;
}
public function hasNext()
{
return count( $this->array ) > $this->index;
}
public function next()
{
$item = $this->array[ $this->index ];
this->$index++;
return $item;
}
}
?>
As you can see, i have no way of adding new items to the given array, but i do have posibilities to read the array like this:
while( $iterator->hasNext() )
$item = $iterator->next();
Now there is again, only one way to add items to myArray in A, namely via the addSomethingToArray method. So that is what an Iterator is, it is somewhat of a shell around arrays, to provide something called encapsulation.
Array is array type, ArrayObject and ArrayIterator are built-in classes, with their instances being object type, that partially behave like arrays on syntax and usage level.
For the classes I think the quick idea can be gained from the interfaces they implement:
class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable {
class ArrayIterator implements SeekableIterator, ArrayAccess, Serializable, Countable {
Both classes implement:
ArrayAccess, so they support array syntax to access values
Countable, so they support count of values, like arrays do
Iterator (though in different ways), so they fit iterable type and can be looped over with foreach and such
One way to look at it, is that classes go through a lot of trouble to work like an array. The point is that being classes, they can be extended and customized.
They would also be inherently interoperable with any code that expects Iterator in general, so the basic use case is just that - wrapping to feed array data into iterator code.
So in a nutshell ArrayObject and ArrayIterator are Do It Yourself arrays (with some implementation differences between the two). Their instances (partially) behave like array type, but as classes they are extensible and as Iterator implementers they are interoperable with code that wants that.
Unless you need a deeply custom behavior and/or Iterator interoperability, sticking with array type is probably the way to go between these.
Notably there are also implementations of collections around, that aim to deliver the class benefits with more friendly abstractions.
array is one the eight primitive types in PHP. Allthough it comes with a lot of built-in utility functions, but they are all procedural.
Both the ArrayObject and the ArrayIterator allow us to make arrays first class citizens in an object oriented program (OOP).
Difference between ArrayObject and the ArrayIterator is that, since ArrayIterator implements SeekableIterator interface, you can do $myArray->seek(10); with ArrayIterator.
An Iterator is an object that enables a programmer to traverse a container, particularly lists. Various types of iterators are often provided via a container's interface.
There is no much difference between ArrayObject and Array as they represent the same things albeit using different object types.
ArrayIterator is an Iterator that iterates over Array-like objects, this includes all objects that implement ArrayAcess and the native Array type.
In fact, when you foreach over an array, PHP internally creates ArrayIterator to do the traversing and transform your code to look as if typed this,
for( $arrayIterator->rewind(); $arrayIterator->valid(); $arrayIterator-
>next())
{ $key = $arrayIteartor->key();
$value = $arrayIterator->current();
}
So you can see, every collection object has an Iterator except for your defined collections which you need to define your own Iterators for.
EDIT:forgot to address the normal array in my answer..
Before you read all this, if your new to php and not trying to do anything tricky just storing values to be used later, then just use the array primitive type.
$data = [1,2,3,4,5];
//or
$data = array(1,2,3,4,5);
Array is the entry point and you should get used to using first them before considering using the others. If you do not understand arrays then you will probably will not understand the benefits of using the others.
( See https://www.w3schools.com/php/php_arrays.asp for a tutorial on arrays. )
Otherwise continue reading...
I have the same question and after coming here decided to just spend some time testing them out and here is my findings and conclusions...
First lets clear up some things that were said by others that I immediately tested.
ArrayObject and ArrayItterator do not protect the data. Both can still be passed by reference in a for-each loop (see down he bottom for example).
Both return true for is_object(), both return false for is_array() and both allow direct access to the values as an array without providing protection for adding values etc. and both can be passed by reference allowing the original data to be manipulated during a foreach loop.
$array = new ArrayIterator();
var_dump(is_array($array)); // false
var_dump(is_object($array)); // true
$array[] = 'value one';
var_dump($array[0]);//string(9) "value one"
$array = new ArrayObject();
var_dump(is_array($array)); // false
var_dump(is_object($array)); // true
$array[] = 'value one';
var_dump($array[0]);//string(9) "value one"
The big difference can be seen in the functions that are available for either of them.
ArrayIteroator has all the functions required to traverse the values such as a foreach loop. ( A foreach loop will call rewind(),valid(),current(),key() methods )
see: https://www.php.net/manual/en/class.iterator.php for an excellent example of the concept (lower level class documentation).
While an ArrayObject can still be iterated over and access values the same way, it does not offer public access to pointer functions.
Object is kind of like adding a wrapper arount the ArrayItterator object and has public getIterator ( void ) : ArrayIterator that will faciliate traversing of the values inside.
You can always get the ArrayItterator From ArrayObject if your really need the added functions.
ArrayItterator is best choice if you have your own pseudo foreach loop for traversing in weird ways and want better control instead of just start to end traversal.
ArrayItterator would also be a good choice for overriding the default array behavior when iterated over by a foreach loop. eg..
//I originally made to this to solve some problem where generic conversion to XML via a foreach loop was used,
//and I had a special case where a particular API wanted each value to have the same name in the XML.
class SameKey extends ArrayIterator{
public function key()
{
return "AlwaysTheSameKey";
}
}
$extendedArrayIterator = new SameKey(['value one','value two','value three']);
$extendedArrayIterator[] = 'another item added after construct';
//according to foreach there all the keys are the same
foreach ($extendedArrayIterator as $key => $value){
echo "$key: ";//key is always the same
var_dump($value);
}
//can still be access as array with index's if you need to differentiate the values
for ($i = 0; $i < count($extendedArrayIterator); $i++){
echo "Index [$i]: ";
var_dump($extendedArrayIterator[$i]);
}
The ArrayObject might be a good choice if you have more high level complexities with itterators going on for example...
//lets pretend I have many custom classes extending ArrayIterator each with a different behavior..
$O = new ArrayObject(['val1','val2','val3']);
//and I want to change the behavior on the fly dynamically by changing the iterator class
if ($some_condition = true) $O->setIteratorClass(SameKey::class);
foreach ($O as $key => $value){
echo "$key: ";//AlwaysTheSameKey:
var_dump($value);
}
One example might be changing the output of the same data set such as having a bunch of custom iterators that will return the values in a different format when traversing the same data set. eg...
class AustralianDates extends ArrayIterator{
public function current()
{
return Date('d/m/Y',parent::current());
}
}
$O = new ArrayObject([time(),time()+37474,time()+37845678]);
//and I want to change the behaviour on the fly dynamically by changing the iterator class
if ($some_condition = true) $O->setIteratorClass(AustralianDates::class);
foreach ($O as $key => $value){
echo "$key: ";//AlwaysTheSameKey:
var_dump($value);
}
Obviously there are probably better ways to do this kind of thing.
In short these are the major major advantages differences I can see.
ArrayItorator
- lower level ability to control or extend & override traversal behaviors.
VS
ArrayObject
- one Container for data but able to change ArrayIterator class.
There are also other differences you might care to inspect but I'd imagine you wont fully grasp them all until you use them extensively.
It appears both objects can be used by reference in a foreach but NOT when using a custom itterator class via an ArrayObject..
//reference test
$I = new ArrayIterator(['mouse','tree','bike']);
foreach ($I as $key => &$value){
$value = 'dog';
}
var_dump($I);//all values in the original are now 'dog'
$O = new ArrayObject(['mouse','tree','bike']);
foreach ($O as $key => &$value){
$value = 'dog';
}
var_dump($O);//all values in the original are now 'dog'
$O->setIteratorClass(SameKey::class);
foreach ($O as $key => &$value){//PHP Fatal error: An iterator cannot be used with foreach by reference
$value = 'dog';
}
var_dump($O);
Recommendation/Conclusion
Use arrays.
If you want to do something tricky then,
I'd recommend always using ArrayIterator to start off with and only move on to ArrayObject if you want to something specific that only ArrayObject can do.
Considering the ArrayObject can make use of any custom ArrayIterators you have created along the way, id say this is the logical path to take.
Hope this helps you as much as it helped me looking into it.
Arrays
An array in PHP is actually an ordered map. A map is a type that
associates values to keys. This type is optimized for several
different uses; it can be treated as an array, list (vector), hash
table (an implementation of a map), dictionary, collection, stack,
queue, and probably more. As array values can be other arrays, trees
and multidimensional arrays are also possible.
The ArrayObject class
This class allows objects to work as arrays.
The ArrayIterator class
This iterator allows to unset and modify values and keys while
iterating over Arrays and Objects.
When you want to iterate over the same array multiple times you need
to instantiate ArrayObject and let it create ArrayIterator instances
that refer to it either by using foreach or by calling its
getIterator() method manually.

Make array keys insensitive in php

Am using DB2 with my PHP. DB2 returns all column names in UPPERCASE. If I use db2_fetch_assoc, then the result would be like this
Array { [USERID] => 4 }
But in my php file, the array values assigned like this and its in camelstyle
$this->userId = $row['userId'];
So it throws the error Error : Undefined index userId
I can use array_change_key_case() function to convert the array to lowercase. But I have hundreds of files which get and assign the array values.
Its not possible to change in all of my files. Also its linux machine.
So is there any function available in php to disable the case sensitivity of array keys.
You can extend ArrayObject from the SPL.
This way at least you only have to "touch" the functions/methods that get the data from the database.
$row = getRow();
echo $row['userId'];
function getRow() {
$row = array ( 'USERID' => 4, 'FOO'=>123, 'BAR'=>456 );
return new UCArrayObject($row);
}
class UCArrayObject extends ArrayObject
{
public function offsetExists ($index) { return parent::offsetExists(strtoupper($index)); }
public function offsetGet($index) { return parent::offsetGet(strtoupper($index)); }
public function offsetSet ($index, $newval) { parent::offsetSet(strtoupper($index), $newval); }
public function offsetUnset ($index) { parent::offsetUnset(strtoupper($index)); }
}
I don't know about DB2, but most libraries will return the rows in the case you specify them in your query, so, you can SELECT USERID, SELECT userid or SELECT UserId, whichever suits you best.
The keys of an array are not case insensitive ever.
It would be possible to write a class that mimics an array (look on PHP.net. you'll have to implement an interface to achieve this). Every value you add to it, can be added to an internal array structure using a lowercase version of the key. When reading a value, you can also use the lowercase version of the specified key. This will essentially make your class behave like a case insensitive array.
A class like this can be used in for-loops too, but unfortunately it cannot be passed to functions that actually require an array parameter.
A different solution: If you have a fairly small amount of queries, and your database layer is nicely separated from the rest of your application, you can apply some sort of translation. Just iterate through the resulting arrays, and map their keys to a specific casing you like, using a translation array. E.g. make an array containing ('lowercase'=>'CamelCase') versions of your field names. That way, you can easily find names and find the right casing for them. Using the found keys, you can construct a new array, before returning it to the requesting code.
Those keys still won't be case insensitive, but they will have the casing you want.
No, there isn't. PHP just don't do that. Array case has to be swapped out on a case-by-case basis.

limiting a collection of objects to a unique set

Currently I have a PHP class called Collection. It uses an array to hold set of unique objects. They are unique, not in the sense that they have different memory addresses (though obviously they do), but in the sense that there are no equivalent objects in the set.
I've been reading about SplObjectStorage which has significant speed advantages over an array and might be easier to maintain than my Collection class. My problem is that SplObjectStorage does not concern itself with equivalency, only identity. For example:
class Foo {
public $id;
function __construct($int){
$this->id=$int;
}
function equals(self $obj){
return $this->id==$obj->id;
}
}
$f1a = new Foo(1);
$f1b = new Foo(1);//equivalent to $f1a
$f2a = new Foo(2);
$f2b = $f2a; //identical to $f2a
$s=new SplObjectStorage;
$s->attach($f1a);
$s->attach($f1b);//attaches (I don't want this)
$s->attach($f2a);
$s->attach($f2b);//does not attach (I want this)
foreach($s as $o) echo $o->id; //1 1 2, but I wish it would be 1 2
So I've been thinking about how to subclass SplObjectStorage so its attach() would be restricted by object equivalency, but so far it involves setting the $data of the object to an "equivalency signature" which seems to require looping through the datastructure until I find (or not) a matching value.
e.g.:
class MyFooStorage extends SplObjectStorage {
function attach(Foo $obj){
$es=$obj->id;
foreach($this as $o=>$data) {//this is the inefficient bit
if($es==$data) return;
}
parent::attach($obj);
$this[$obj]=$es;
}
}
Is there a better way?
If the only thing that defines equality is relative to another object, then I am afraid that what you want is impossible. Think about it, there is no way to determine that an object is already included in the array unless I check every object, so I will have a complexity of O(n) no matter what.
However, if you make the equality absolute then this is possible. In order to do that, you will have to produce a hash value for each of the objects. Two objects will be equal if and only if their hashes are equal. Once you have that, then you can achieve O(1) with a HashMap.
Under the hoods, this is exactly what SplObjectStorage does, by taking the address of an object as its hash value.

When should I use stdClass and when should I use an array in php oo code?

In the middle of a period of big refactoring at work, I wish to introduce stdClass ***** as a way to return data from functions and I'm trying to find non-subjective arguments to support my decision.
Are there any situations when would it be best to use one instead of the other ??
What benefits would I get to use stdClass instead of arrays ??
Some would say that functions have to be as little and specific to be able to return one single value. My decision to use stdClass is temporal, as I hope to find the right Value Objects for each process on the long run.
The usual approach is
Use objects when returning a defined data structure with fixed branches:
$person
-> name = "John"
-> surname = "Miller"
-> address = "123 Fake St"
Use arrays when returning a list:
"John Miller"
"Peter Miller"
"Josh Swanson"
"Harry Miller"
Use an array of objects when returning a list of structured information:
$person[0]
-> name = "John"
-> surname = "Miller"
-> address = "123 Fake St"
$person[1]
-> name = "Peter"
-> surname = "Miller"
-> address = "345 High St"
Objects are not suitable to hold lists of data, because you always need a key to address them. Arrays can fulfill both functions - hold arbitrary lists, and a data structure.
Therefore, you can use associative arrays over objects for the first and third examples if you want to. I'd say that's really just a question of style and preference.
#Deceze makes a number of good points on when to use an object (Validation, type checking and future methods).
Using stdClass to fulfill the same function as an array is not very useful IMHO, it just adds the overhead of an object without any real benefit. You're also missing out on many useful array functions (e.g. array_intersect). You should at least create your own class to enable type checking, or add methods to the object to make it worth using an object.
I don't think there is any reasonable advantage of using a stdClass over an array as long as your sole intention is to return multiple arbitrary datatypes from a function call.
Since you cannot technically return multiple values natively, you have to use a container that can hold all other datatypes available in PHP. That would be either an object or an array.
function fn1() { return array(1,2); }
function fn2() { return array('one' => 1, 'two' => 2); }
function fn3() { return (object) array(1,2); }
function fn4() { return (object) array('one' => 1, 'two' => 2); }
All of the above would work. The array is a tiny negligible fraction faster and less work to type. It also has a clearly defined purpose in contrast to the generic stdClass (which is a bit wishywashy, isnt it). Both only have an implicit interface, so you will have to look at the docs or the function body to know what they will contain.
If you want to use objects at any cost, you could use ArrayObject or SplFixedArray, but if you look at their APIs would you say you need their functionality for the simple task of returning random multiple values? I don't think so. Don't get me wrong though: if you want to use stdClass, then use it. It's not like it would break anything. But you also would not gain anything. To add at least some benefit, you could create a separate class named ReturnValues for this.
Could be a simple tagging class
class ReturnValues {}
or something more functional
class ReturnValues implements Countable
{
protected $values;
public function __construct() { $this->values = func_get_args(); }
public function __get($key) return $this->values[$key]; }
public function count() { return count($this->values); }
}
Granted, it doesn't do much and getting the values out of it is still done through an implict interface, but at least the class has a more clearly defined responsibility now. You could extend from this class to create ReturnValue objects for particular operations and give those an explicit interface:
class FooReturnValues extends ReturnValues
{
public function getFoo() { return $this->values['foo']; }
public function getBar() { return $this->values['foo']; }
}
Now the developer just has to look at the API to know which multiple values foo() will return. Of course, having to write concrete ReturnValue classes for each and every operation that might return multiple values could become tedious quickly. And personally, I find this overengineered for the initial purpose.
Anyway, hope that makes any sense.
Well, there are 3 differences:
they have an identity. which is why the default for passing array arguments is call by value and for objects call by sharing.
there is a semantical difference. If you use an object, anyone who reads the code understand, that the value represents the model some sort of entitity, while an array is supposed to act as a collection or a map
And last but not least, refactoring becomes signifficantly easier. If you want to use a concrete class rather than stdClass, all you have to do is to instantiate another class. Which also allows you to add methods.
greetz
back2dos
The only OBJECTIVE vote of confidence I can find is:
json_decode uses stdClass by default so us mortals in userland should use stdClass for similar situations.
I find stdClass objects over arrays useful when I need to keep my code clean and somewhat sentence-like readable. Take for example function getProperties() which returns a set of properties, say data about a person (name, age, sex). If getProperties() would return an associative array, when you want to use one of the returned properties, you would write two instructions:
$data = getProperties();
echo $data['name'];
On the other hand, if getProperties() returns a stdClass then you could write that in just one instruction:
echo getProperties()->name;
In tests of array vs stdclass they way php handles dynamic properties is slower then associative arrays. I'm not saying this to argue micro optimization but rather if your going to do this your better off defining a dataclass with no methods and set public properties. Esp if you are using php 5.4+. Under the hood defined properties are mapped directly to a c array with no hashtable where as dynamic ones need to use a hash table.
This has the added bonus of later becoming a full class without any major interface reworking.

Categories