Make array keys insensitive in php - 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.

Related

php intersection of array of slightly different objects

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.

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

Using an Array as the Key for an Array in PHP

I need to create an association between an Array and a Number; as PHP lacks a Map type, I am trying using an array to achieve this:
$rowNumberbyRow = array();
$rowNumberByRow[$rowData] = $rowNumber;
However, when I evaluate the code, I get the following Error:
Warning: Illegal offset type
Just to note, the data stored in the array ($rowData) does not have any 'unique' values that I can use as a key for the $rowNumberByRow Array.
Thanks!
UPDATE:
To answer some of my commenters, I am trying to create a lookup table so that my application can find the row number for a given row in O(1) time.
PHP does have a map Class: It's called SplObjectStorage. It can be accessed with exactly the same syntax as a general array is (see Example #2 on the reference).
But to use the class you will have to use the ArrayObject class instead of arrays. It is handled exactly the same way arrays are and you can construct instances from arrays (e.g. $arrayObject = new ArrayObject($array)).
If you don't want to use those classes, you can also just create a function that creates unique hash-strings for your indexes. For example:
function myHash($array){
return implode('|',$array);
}
$rowNumberByRow[myHash($array)] = $rowNumber;
You will of course have to make sure that your hashes are indeed unique, and I would strongly suggest you use the SplObjectStorage and maybe read a little bit more about the SPL classes of php.
Why not just store the row number in the array? e.g:
$rowData['rowNumber'] = $rowNumber;
You could instead serialize the array, e.g:
$rowNumberByRow[serialize($rowData)] = $rowNumber;
However that's pretty inefficient.
In php you can use only scalar values as an array keys.
If your $rowNumber is unique - then you'd try to use the opposite relation direction. If it is not unique - then you don't have any possible solution I know.
The answer has been alredy given and accepted, but while i was searching for a similar problem, i found this question, and i felt like i should drop a line: when someone wants to use an array with values as keys for another array, it would be useful to use the function array_combine.
If i got the arrays correctly, you could use:
$rowNumberByRow = array_combine($rowData, $rowNumber);
Please take a look at the PHP manual to see some info about permitted values for the keys :)

PHP class with property which can be either an int or an array

I have a class (say Product) with a property (say product_id) and has methods to retrieve information from multiple database tables for given product ID. Now I want the class methods to handle one product ID as well as an array of product IDs (in order to save the number of queries). Also the output will vary depending on the input i.e. for array as input, I'll have as output an array indexed with product ids, whereas for a single ID, I might not need this array.
What is the clean way to design such a class?
Here are a couple of things I've thought of:
Have separate methods with indicative names for single and multiple ids (clean but duplication)
Have only one method for both types of input, check input type...process...format output as per the input (not really clean)
Internally, always work with an array of values. If there's only one value in the array, so be it, but that doesn't need to change your logic at all.
For input/output, you may want to make your methods accept a single value, which you're going to turn into an array:
public function foo($val) {
$val = (array)$val;
...
}
And/or, you might create a "singular convenience wrapper" that just makes it clear that it returns or accepts single results:
public function foos(array $vals) {
...
return /* array of elements */;
}
public function foo($val) {
return current($this->foos(array($val)));
}

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