PHP array_merge: argument not an array? - php

I'm getting some weird behaviour in PHP that I just can't understand.
$count=0;
$temp=array(); //this is definitely a new variable, not that it should matter
foreach($array as $arr) {
if ($arr->bbcode != $previous_bb) {
$previous_bb=$arr->bbcode;
//stuff
$temp=array_merge($temp,$arr);
}
//stuff
}
I've tried to simplify the code a little and just keep what's essential. $array is a 2-D array (so each $arr has some attributes like the bbcode that you see). It complains that argument 1, i.e. $temp, is not an array. Typecasting it to array gives bogus results. Of course, this is within other code, which I can give more details of if needed, but any ideas? I've used the exact same sort of code and syntax in other places and it doesn't complain...
EDIT: Feel free to downvote liberally, had a memory lapse about what I had been working with and how I'd been doing things. Never had to ask a programming question before (in several years), thanks a ton guys, you are immensely fast!

Let's look at your two arguments.
$temp is initialised as array(), and repeatedly assigned to the return value of array_merge which (unless things go wrong) is always an array.
$arr. Well, it's in the name, right? That's about as reliable as $two = 3;. You are accessing $arr->bbcode so it is clearly an object and not an array.
Did you mean $temp[] = $arr;?

You are trying to merge an object ($arr) with an array ($temp). PHP should complain that $arr is not an array. See the example code below:
php > $obj = new StdClass();
php > $obj->property = "value";
php > $arr = [];
php > array_merge($arr, $obj);
Warning: array_merge(): Argument #2 is not an array in php shell code on line 1
Call Stack:
33.2510 230352 1. {main}() php shell code:0
33.2510 230960 2. array_merge() php shell code:1
Typecasting in php is always a bit tricky, if you do so check the type juggling documentation to see what happens when.
Before trying to optimize your code, what do you want to achieve? A new list which is cleaned of duplicate bb codes?

Related

ARRAY. Is there a difference between $variable=[]; and $variable = array(); [duplicate]

In certain other languages (AS3 for example), it has been noted that initializing a new array is faster if done like this var foo = [] rather than var foo = new Array() for reasons of object creation and instantiation. I wonder whether there are any equivalences in PHP?
class Foo {
private $arr = array(); // is there another / better way?
}
$myArray = [];
Creates empty array.
You can push values onto the array later, like so:
$myArray[] = "tree";
$myArray[] = "house";
$myArray[] = "dog";
At this point, $myArray contains "tree", "house" and "dog". Each of the above commands appends to the array, preserving the items that were already there.
Having come from other languages, this way of appending to an array seemed strange to me. I expected to have to do something like $myArray += "dog" or something... or maybe an "add()" method like Visual Basic collections have. But this direct append syntax certainly is short and convenient.
You actually have to use the unset() function to remove items:
unset($myArray[1]);
... would remove "house" from the array (arrays are zero-based).
unset($myArray);
... would destroy the entire array.
To be clear, the empty square brackets syntax for appending to an array is simply a way of telling PHP to assign the indexes to each value automatically, rather than YOU assigning the indexes. Under the covers, PHP is actually doing this:
$myArray[0] = "tree";
$myArray[1] = "house";
$myArray[2] = "dog";
You can assign indexes yourself if you want, and you can use any numbers you want. You can also assign index numbers to some items and not others. If you do that, PHP will fill in the missing index numbers, incrementing from the largest index number assigned as it goes.
So if you do this:
$myArray[10] = "tree";
$myArray[20] = "house";
$myArray[] = "dog";
... the item "dog" will be given an index number of 21. PHP does not do intelligent pattern matching for incremental index assignment, so it won't know that you might have wanted it to assign an index of 30 to "dog". You can use other functions to specify the increment pattern for an array. I won't go into that here, but its all in the PHP docs.
In ECMAScript implementations (for instance, ActionScript or JavaScript), Array() is a constructor function and [] is part of the array literal grammar. Both are optimized and executed in completely different ways, with the literal grammar not being dogged by the overhead of calling a function.
PHP, on the other hand, has language constructs that may look like functions but aren't treated as such. Even with PHP 5.4, which supports [] as an alternative, there is no difference in overhead because, as far as the compiler/parser is concerned, they are completely synonymous.
// Before 5.4, you could only write
$array = array(
"foo" => "bar",
"bar" => "foo",
);
// As of PHP 5.4, the following is synonymous with the above
$array = [
"foo" => "bar",
"bar" => "foo",
];
If you need to support older versions of PHP, use the former syntax. There's also an argument for readability but, being a long-time JS developer, the latter seems rather natural to me.  I actually made the mistake of trying to initialise arrays using [] when I was first learning PHP.
This change to the language was originally proposed and rejected due to a majority vote against by core developers with the following reason:
This patch will not be accepted because slight majority of the core developers voted against. Though if you take a accumulated mean between core developers and userland votes seems to show the opposite it would be irresponsible to submit a patch witch is not supported or maintained in the long run.
However, it appears there was a change of heart leading up to 5.4, perhaps influenced by the implementations of support for popular databases like MongoDB (which use ECMAScript syntax).
Prior to PHP 5.4:
$myArray = array();
PHP 5.4 and higher
$myArray = [];
In PHP an array is an array; there is no primitive vs. object consideration, so there is no comparable optimization to be had.
What you're doing is 100% correct.
In terms of nice naming it's often done that private/protected properties are preceded with an underscore to make it obvious that they're not public. E.g. private $_arr = array() or public $arr = array()
Initializing a simple array :
<?php $array1=array(10,20,30,40,50); ?>
Initializing array within array :
<?php $array2=array(6,"santosh","rahul",array("x","y","z")); ?>
Source : Sorce for the code
There is no other way, so this is the best.
Edit: This answer is not valid since PHP 5.4 and higher.
Try this:
$arr = (array) null;
var_dump($arr);
// will print
// array(0) { }
Do not do this:
$arrTst = array( 'IdxKeyOne' => null, 'IdxKeyTwo' => null, 'IdxKeyThr' => null );
There's no such thing as "initializing" an array's index-keys with dummy/placeholder values. print_r gives:
Array (
[IdxKeyOne] =>
[IdxKeyTwo] =>
[IdxKeyThr] =>
)
where the elements exist, having defined keys but null-values. When using the array later, you would have to drop the dummy-row anyway.

Memory leak?! Is Garbage Collector doing right when using 'create_function' within 'array_map'?

I found following solution here on StackOverflow to get an array of a specific object property from array of objects: PHP - Extracting a property from an array of objects
The proposed solution is to use array_map and within create a function with create_function as following:
$catIds = array_map(create_function('$o', 'return $o->id;'), $objects);
What happens?: array_map runs through each array element in this case a stdClass object. First it creates a function like this:
function($o) {
return $o->id;
}
Second it calls this function for the object in the current iteration. It works, it works nearly same like this similar solution:
$catIds = array_map(function($o) { return $o->id; }, $objects);
But this solution is only running in PHP version >= 5.3 because it uses the Closure concept => http://php.net/manual/de/class.closure.php
Now the real problem:
The first solution with create_function increases the memory, because the created function will be written to the memory and not be reused or destroyed. In the second solution with Closure it will.
So the solutions gives the same results but have different behaviors with respect to the memory.
Following example:
// following array is given
$objects = array (
[0] => stdClass (
[id] => 1
),
[1] => stdClass (
[id] => 2
),
[2] => stdClass (
[id] => 3
)
)
BAD
while (true)
{
$objects = array_map(create_function('$o', 'return $o->id;'), $objects);
// result: array(1, 2, 3);
echo memory_get_usage() ."\n";
sleep(1);
}
4235616
4236600
4237560
4238520
...
GOOD
while (true)
{
$objects = array_map(function($o) { return $o->id; }, $objects);
// result: array(1, 2, 3);
echo memory_get_usage() ."\n";
sleep(1);
}
4235136
4235168
4235168
4235168
...
I spend so many time to find this out and now I want to know, if it's a bug with the garbage collector or do I made a mistake?
And why it make sense to leave the already created and called function in memory, when it'll never be reuse?
Here is a running example: http://ideone.com/9a1D5g
Updated: When I recursively search my code and it's dependencies e.g. PEAR and Zend then I found this BAD way too often.
Updated: When two functions are nested, we proceed from the inside out in order to evaluate this expression. In other words, it is first starting create_function (once) and that returning function name is the argument for the single call of array_map. But because GC forget to remove it from memory (no pointer left to the function in memory) and PHP not be able to reuse the function already located in memory let me think that there is an error and not only a thing with "bad performance". This specific line of code is an example in PHPDoc and reused in so many big frameworks e.g. Zend and PEAR and more. With one line more you can work around this "bug", check. But I'm not searching for a solution: I'm searching for the truth. Is it a bug or is it just my approach. And latter I could not decide yet.
In the case of create_function() a lambda-style function is created using eval(), and a string containing its name is returned. That name is then passed as argument to the array_map() function.
This differs from the closure-style anonymous function where no string containing a name is used at all. function($o) { return $o->id; } IS the function, or rather an instance of the Closure class.
The eval() function, inside create_function(), executes a piece of PHP code which creates the wanted function. Somewhat like this:
function create_function($arguments,$code)
{
$name = <_lambda_>; // just a unique string
eval('function '.$name.'($arguments){$code}');
return $name;
}
Note that this is a simplification.
So, once the function is created it will persist until the end of the script, just like normal functions in a script. In the above BAD example, a new function is created like this on every iteration of the loop, taking up more and more memory.
You can, however, intentionally destroy the lambda-style function. This is quite easy, just change the loop to:
while (true)
{
$func = create_function('$o', 'return $o->id;');
$objects = array_map($func, $objects);
echo memory_get_usage() ."\n";
sleep(1);
}
The string containting the reference (= name) to the function was made expliciet and accessible here. Now, every time create_function() is called, the old function is overwritten by a new one.
So, no, there's no 'Memory leak', it is meant to work this way.
Of course the code below is more efficient:
$func = create_function('$o', 'return $o->id;');
while (true)
{
$objects = array_map($func, $objects);
echo memory_get_usage() ."\n";
sleep(1);
}
And should only be used when closure-style anonymous function are not supported by your PHP version.
Don't use create_function() if you can avoid it. Particularly not repeatedly. Per the big yellow Caution box in the PHP manual:
...it has bad performance and memory usage characteristics.
OK, I think the problem is, that first solution with create_function is running on older versions of PHP and the second solution doesn't increase the memory unnecessary. But let's have a look at first solution. The create_function method is called inside the array_map, namely for each while iteration. If we want a solution to work with older PHP versions and without increasing memory we have to do following to the older function instance on each while iteration:
$func = create_function('$o', 'return $o->id;');
$catIds = array_map($func, $objects);
That's all. So simple.
But it also isn't answering the question at all. What remains is the question if it is a bug with PHP or a feature. For my understanding that way to write the result of create_function in a variable SHOULD be the same as put it directly as parameter in array_map, isn't it?

php get array elememnt using $$

i know this
$var1 = "10";
$var2 = "var1";
then
echo $$var2 gives us 10
i want to this with array
i have array
$intake_arr = array(5=>10,7=>20,8=>30,9=>40,10=>50,11=>60,12=>70);
i have some logic that will pick one array from set of array , all array will look like $intake_arr
if i do this $target_arr = "intake_arr";
then can $$target_arr[5] will yield 10? i tried but i didnt that 10 value, how can i achieve this with array
Your statement ($$target_arr[5]) is ambiguous. PHP doesn't know what you actually want to say: Do you mean: use $target_arr[5]'s value and prepend the $, to use that as a variable, or do you want to use the value of $target_arr, and get the fifth element of that array?
Obviously it's the latter, but PHP doesn't know that. In order to disambiguate your statement, you have to use curly braces:
${$target_arr}[5];
That'll yield 10. See the manual on variable variables for details
Note:
As people said in comments, and deleted answers: variable variables, like the one you're using is risky business. 9/10 it can, and indeed should be avoided. It makes your code harder to read, more error prone and, in combination with the those two major disadvantages, this is the killer: it makes your code incredibly hard to debug.
If this is just a technical exercise, consider this note a piece of friendly advice. If you've gotten this from some sort of tutorial/blog or other type of online resource: never visit that site again.
If you're actually working on a piece of code, and you've decided to tackle a specific problem using variable vars, then perhaps post your code on code-review, and let me know, I'll have a look and try to offer some constructive criticism to help you on your way, towards a better solution.
Since what you're actually trying to do is copying an array into another variable, then that's quite easy. PHP offers a variety of ways to do that:
Copy by assignment:
PHP copies arrays on assignment, by default, so that means that:
$someArray = range(1,10);//[1,2,3,4,5,6,7,8,9,10]
$foo = $someArray;
Assigns a copy of $someArray to the variable $foo:
echo $foo[0], ' === ', $someArray[0];//echoes 1 === 1
$foo[0] += 123;
echo $foo[0], ' != ', $someArray[0];//echoes 123 != 1
I can change the value of one of the array's elements without that affecting the original array, because it was copied.
There is a risk to this, as you start working with JSON encoded data, chances are that you'll end up with something like:
$obj = json_decode($string);
echo get_class($obj));//echoes stdClass, you have an object
Objects are, by default, passed and assigned by reference, which means that:
$obj = new stdClass;
$obj->some_property = 'foobar';
$foo = $obj;
$foo->some_property .= '2';
echo $obj->some_property;//echoes foobar2!
Change a property through $foo, and the $obj object will change, too. Simply because they both reference exactly the same object.
Slice the array:
A more common way for front-end developers (mainly, I think, stemming from a JS habbit) is to use array_slice, which guarantees to return a copy of the array. with the added perk that you can specify how many of the elements you'll be needing in your copy:
$someArray = range(1,100);//"large" array
$foo = array_slice($someArray, 0);//copy from index 0 to the end
$bar = array_slice($someArray, -10);//copy last 10 elements
$chunk = array_slice($someArray, 20, 4);//start at index 20, copy 4 elements
If you don't want to copy the array, but rather extract a section out of the original you can splice the array (as in split + slice):
$extract = array_splice($someArray, 0, 10);
echo count($someArray);//echoes 90
This removes the first 10 elements from the original array, and assigns them to $extract
Spend some time browsing the countless (well, about a hundred) array functions PHP offers.
${$target_arr}[5]
PHP: Variable variables
Try this one:
$intake_arr = array(5=>10,7=>20,8=>30,9=>40,10=>50,11=>60,12=>70);
$target_arr = 'intake_arr';
print ${$target_arr}[5]; //it gives 10
For a simple variable, braces are optional.But when you will use a array element, you must use braces; e.g.: ${$target_arr}[5];.As a standard, braces are used if variable interpolation is used, instead of concatenation.Generally variable interpolation is slow, but concatenation may also be slower if you have too many variables to concatenate.Take a look here for php variable variables http://php.net/manual/en/language.variables.variable.php

"Array sizes are inconsistent" error while using array_multisort

I am trying to sort a multidimensional array by multiple values but I keep getting the error:
Warning: array_multisort() [function.array-multisort]: Array sizes are inconsistent in -- on line 19
Line 19 is where I call the array_multisort function:
array_multisort($column1, $column2, $column3, $row);
I have been unable to replicate the issue in a test, so I haven't had much luck in solving the issue.
So basically I am saving a MySql table as a multidimensional associative array. Then I am trying to sort the rows by three different columns. I have checked and all of the arrays passed into the array_multisort() function are the same size. I checked both by manually looking through every row and by using sizeof().
Any ideas what could be causing this and/or what the solution is?
to answer your original question, this normally happens with an uninitiated variable.
For example:
foreach ($arr_this_referers as $int_key => $arr_row) {
$arr_vol[$int_key] = $arr_row['int_cnt'];
}
will cause WARNING due to uninitiated variable $arr_vol but initialize variable before the for loop:
$arr_vol = array();
foreach ($arr_this_referers as $int_key => $arr_row) {
$arr_vol[$int_key] = $arr_row['int_cnt'];
}
array_multisort($arr_vol, SORT_DESC, $arr_this_referers);
... & warning disappears, hope this helps.
I ended just using uasort() instead. it gave me no problems at all and it was pretty straight forward to set up the cmp logic.
Still no idea what the issue with array_multisort() was.

PHP to Python Code Differences - Arrays, Foreach Loops

I hope this question is phrased appropriately to the policies of this site.
I am trying to convert a piece of Python Code to PHP code. I have gotten almost every function translated except I cannot figure out how Arrays and Foreach loops are different in PHP vs Python.
qstid = dbinputsurveyid+'X'+str(question.gid)+'X'+str(question.qid)
index=columns.index(qstid)
for i,a in enumerate(data[index]):
if a!=None and a!='':
answer=int(data[index][i])
answerCodes=list(answersCode[question.qid])
answerindex = answerCodes.index(str(answer))
answerorder = answersOrder[question.qid][a]
addAnswers(db, data[0][i], question.sid, question.gid, question.qid, question.type, answers[question.qid][answerindex], None,answerorder, None, None,None)
From some of the reading I have done. I think enumerate in python is the equivalent to a foreach loop in PHP. But im not sure how "i" and "a" come into play in the code above. They dont seem to be defined like you would in PHP. Any help or insight is appreciated.
The notation i, a in that loop gives you access to the index and values of the list.
From the Python docs:
When looping through a sequence, the position index and corresponding
value can be retrieved at the same time using the enumerate()
function.
So, in Python you'd have:
for i,a in enumerate( ['some', 'list'])
Which would be equivalent to PHP:
$array = ['some', 'array'];
// Or, for PHP < 5.4: $array = array( 'some', 'array');
foreach( $array as $i => $a)

Categories