sorting a strange array of objects in PHP - php

I'm editing someone else's code here:
foreach($list as $items) {
// displays items names and images etc
}
and within the foreach() loop I can see the name using:
echo $items[0]->name
and looking at the contents of $items it looks like this:
Array ( [0] => stdClass Object ( [id] => 7 [name] => Bench Scales // ..etc..
But I can't seem to reference name outside the loop
$list[0]->name // doesn't work
So I'm kinda stuck at this point when trying to sort by name, Yep I've looked up usort() and am happy with the concept of sorting by name, but am unable to sort this array of objects? by name. Any help most welcome
Above the foreach() loop I tried something like this, but no luck:
function cmp($a,$b) { return strcmp($a->name, $b->name); }
usort($list,"cmp");

This example:
$list[0]->name; // doesn't work
Shouldnt work Remember that when you're inside a foreach, you're one level nested when you access the iterable such as $item. Therefore
Assuming that the array has numeric indicies and that The 0th value in $list is an object this would work:
$list[0][0]->name;

To me (and I'm kind of tired right now) this doesn't look like a sort issue. $list is a collection (obviously) and when you run it through the foreach loop, each iteration is giving you a single object array to work with, which is why your first example works. $list is an array of arrays, so you need one more level of "access" to get what you want.

Related

Alternative way of accessig an array within array in PHP

I'm trying to access an array within another array (basically, a two dimensional array). However, the usual way of doing this ($myarray[0][0]) doesn't work for me.
The reason is because I want to create a recursive function which, in each call, should dive deeper and deeper into a array (like, on first call it should look at $myarray[0], on second call it should look at $myarray[0][0] and so on).
Is there any alternative way of accessing an array within array?
Thanks.
Traverse the array by passing always a subarray of it to the recursive function.
function f(array &$arr)
{
// Some business logic ...
// Let's go into $arr[0]
if(is_array($arr[0]))
f($arr[0]);
}
f($myarray);

Create associative array from numeric array and function?

I have a numeric array with codes like this: array('123', '333', '444');
I also have a function that given a code returns a name, so myFunc('123') would return 'soap'
I'd like to generate an associative array containing codes as keys and names as values. Is there any function that would allow me to do this? I know a foreach loop would do it but I wonder if there's some made function for this. Saw some methods like array_map but they don't seem to fit my needs.
array_combine($arr, array_map('myFunc', $arr))
But two functions, not one ;-) Still oneliner though

Creating an associative array from an array, based on the array - PHP

I have a unique issue that I have never heard of this being possible to do before:
So essentially I have a function that takes in a an array of arguments such as:
function someFunction(array $arguments){}
and gives me an array back as such:
array('option1', 'option2', 'options3', ...);
I then need to take that array and loop through it creating an associative array such as:
array('option1' => call_come_method('option1'), .... );
heres the kicker, you will never know how many arguments a user passes into the function, yet each one needs to created into a key=>value arrangement as seen above.
Now i did some research and I was told the $argv command in php, how ever where I am stumped is how to implement it in this case.
So if any one can give me any pointers I would be appreciative.
This is a lot easier than you think. First use array_flip to switch the array's keys and values.
$newArray = array_flip($arguments);
Then loop though it and call the method:
foreach($newArray as $key=>&$val){
$val = call_come_method($key);
}
The &, makes it a reference, so the array value is updated.
DEMO: http://codepad.org/giL1KPA3
UPDATE: You don't even need array_flip, you just need a for loop.
$newArray = array();
foreach($arguments as $val){
$newArray[$val] = call_come_method($val);
}
DEMO: http://codepad.org/AQ1gWrou
you will never know how many arguments a user passes into the function
FYI, you get to know it with func_get_args().
This way you don't need to provide your function with an $arguments parameter, but you just leave it empty.

Why does the sort order of multidimensional child arrays revert as soon as foreach loop used for sorting ends?

I have a very strange array sorting related problem in PHP that is driving me completely crazy. I have googled for hours, and still NOTHING indicates that other people have this problem, or that this should happen to begin with, so a solution to this mystery would be GREATLY appreciated!
To describe the problem/question in as few words as possible: When sorting an array based on values inside a multiple levels deeply nested array, using a foreach loop, the resulting array sort order reverts as soon as execution leaves the loop, even though it works fine inside the loop. Why is this, and how do I work around it?
Here is sample code for my problem, which should hopefully be a little more clear than the sentence above:
$top_level_array = array('key_1' => array('sub_array' => array('sub_sub_array_1' => array(1),
'sub_sub_array_2' => array(3),
'sub_sub_array_3' => array(2)
)
)
);
function mycmp($arr_1, $arr_2)
{
if ($arr_1[0] == $arr_2[0])
{
return 0;
}
return ($arr_1[0] < $arr_2[0]) ? -1 : 1;
}
foreach($top_level_array as $current_top_level_member)
{
//This loop will only have one iteration, but never mind that...
print("Inside loop before sort operation:\n\n");
print_r($current_top_level_member['sub_array']);
uasort($current_top_level_member['sub_array'], 'mycmp');
print("\nInside loop after sort operation:\n\n");
print_r($current_top_level_member['sub_array']);
}
print("\nOutside of loop (i.e. after all sort operations finished):\n\n");
print_r($top_level_array);
The output of this is as follows:
Inside loop before sort operation:
Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_2] => Array
(
[0] => 3
)
[sub_sub_array_3] => Array
(
[0] => 2
)
)
Inside loop after sort operation:
Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_3] => Array
(
[0] => 2
)
[sub_sub_array_2] => Array
(
[0] => 3
)
)
Outside of loop (i.e. after all sort operations finished):
Array
(
[key_1] => Array
(
[sub_array] => Array
(
[sub_sub_array_1] => Array
(
[0] => 1
)
[sub_sub_array_2] => Array
(
[0] => 3
)
[sub_sub_array_3] => Array
(
[0] => 2
)
)
)
)
As you can see, the sort order is "wrong" (i.e. not ordered by the desired value in the innermost array) before the sort operation inside the loop (as expected), then is becomes "correct" after the sort operation inside the loop (as expected).
So far so good.
But THEN, once we're outside the loop again, all of a sudden the order has reverted to its original state, as if the sort loop didn't execute at all?!?
How come this happens, and how will I ever be able to sort this array in the desired way then?
I was under the impression that neither foreach loops nor the uasort() function operated on separate instances of the items in question (but rather on references, i.e. in place), but the result above seems to indicate otherwise? And if so, how will I ever be able to perform the desired sort operation?
(and WHY doesn't anyone else than me on the entire internet seem to have this problem?)
PS.
Never mind the reason behind the design of the strange array to be sorted in this example, it is of course only a simplified PoC of a real problem in much more complex code.
Your problem is a misunderstanding of how PHP provides your "value" in the foreach construct.
foreach($top_level_array as $current_top_level_member)
The variable $current_top_level_member is a copy of the value in the array, not a reference to inside the $top_level_array. Therefore all your work happens on the copy and is discarded after the loop completes. (Actually it is in the $current_top_level_member variable, but $top_level_array never sees the changes.)
You want a reference instead:
foreach($top_level_array as $key => $value)
{
$current_top_level_member =& $top_level_array[$key];
EDIT:
You can also use the foreach by reference notation (hat tip to air4x) to avoid the extra assignment. Note that if you are working with an array of Objects, they are already passed by reference.
foreach($top_level_array as &$current_top_level_member)
To answer you question as to why PHP defaults to a copy instead of a reference, it's simply because of the rules of the language. Scalar values and arrays are assigned by value, unless the & prefix is used, and objects are always assigned by reference (as of PHP 5). And that is likely due to a general consensus that it's generally better to work with copies of everything expect objects. BUT--it is not slow like you might expect. PHP uses a lazy copy called copy on write, where it is really a read-only reference. On the first write, the copy is made.
PHP uses a lazy-copy mechanism (also called copy-on-write) that does
not actually create a copy of a variable until it is modified.
Source: http://www.thedeveloperday.com/php-lazy-copy/
You can add & before $current_top_level_member and use it as reference to the variable in the original array. Then you would be making changes to the original array.
foreach ($top_level_array as &$current_top_level_member) {

Trying to access object element within an array

I'm using a framework at work that I'm slightly unfamiliar with and trying to access elements of an object that are stored within an array called $items. I've tried die(print_r($items[0])) to try to get the first element but it says 0 is an undefined index. Here is the result of print_r($items):
Any help is much appreciated. If you have any questions I'll gladly answer because I know this is a bit vague. I think it would take up way too much space to explain how this framework actually works.
I figured out that the first element is 2 and not 0, but I'm still unable to access any of the elements within the object. When I tried print_r($items[2]->fields) it didn't return anything, just a blank page.
I think this is what you want:
$item = current($items);
foreach ($item->fields as $key => $val) {
echo "$key => $val\n";
}
Update:
It seems like you cannot get $item->fields since it is a protected property of Dase_DBO_Project object:
[fields:protected] => Array
I don't see any element with index 0 in your array, only keys 5, 4, 3 and 2. To get the first item from array use current($items) or reset($items).
Your array listed here does not have an index of 0 (For more help look here: http://php.net/manual/en/language.types.array.php)
Rather than attempting to access each item with the index. Why don't you use a foreach?
foreach($items as $item)
{
//Do what you want with each object here
var_dump($item);
}
This will allow you to access each object without using the index. For more information using foreach take a look here: http://us3.php.net/manual/en/control-structures.foreach.php
Cheers!

Categories