CArrayDataProvider sorting broken

Hi,

i was playing around with CArrayDataProvider and discovered that a php error shows up when using sort functionality


Parameter 1 to array_multisort() expected to be a reference, value given

The problem is


call_user_func_array('array_multisort', $args);

inside the sortData method.

After asking the big oracle (thus: google) it doesn’t seem to be a bug in yii but in php. Sorry, i ment a feature that works as designed, but the behavior changes from time to time…

To make it short: there were already some tickets/discussions going on about the behavior of call_user_func_array / array_multisort (see #49353, or #49069 or #49241 ). As mentioned there it’s working as designed since PHP 5.3 (i’m running 5.3.1) and it was only possible by accident that arrays could be passed by value to array_multisort instead of by reference in PHP <= 5.2.

Therefore the yii code doesn’t work, because it passes them by value. At php.net they say everythings fine now and working as designed, but to make it work i not only have to pass the arrays by reference but also the SORT_ flags… wtf? Have you ever passed such a flag by reference?

I’M TALKING TO MUCH :D

I wanted to create a ticket for this, but thought it would be useful to discuss a proper solution here. Maybe a good way to avoid using ‘call_user_func_array’ completly?

If you want to dive into this topic i’ll make it easy so you don’t have to search the original code ^^

Here it is:




	protected function sortData($directions)

	{

		if(empty($directions))

			return;

		$args=array();

		foreach($directions as $name=>$descending)

		{

			$column=array();

			foreach($this->rawData as $index=>$data)

				$column[$index]=is_object($data) ? $data->$name : $data[$name];

			$args[]=$column;

			$args[]=$descending ? SORT_DESC : SORT_ASC;

		}

		$args[]=&$this->rawData;

		call_user_func_array('array_multisort', $args);

	}



I have also done a quick fix, but it looks nasty:


	protected function sortData($directions)

	{

		if(empty($directions))

			return;

		$args=array();

		$args_collect=array(); // Long story - we are collecting every argument in a second array just because after the unset() below php would transfer the reference in $args[] into a value

		foreach($directions as $name=>$descending)

		{

			$column=array();

			foreach($this->rawData as $index=>$data)

				$column[$index]=is_object($data) ? $data->$name : $data[$name];

			$args[]=&$column;

			$args_collect[]=&$column; // Now by reference

			$sortflag=$descending ? SORT_DESC : SORT_ASC;

			$args[]=&$sortflag; // Yes sir, even the flag has to be passed by reference

			$args_collect[]=&$sortflag;

			unset($column,$sortflag); // Unset vars otherwise we'd always get the same content (because of reference)

		}

		$args[]=&$this->rawData;

		call_user_func_array('array_multisort', $args);

	}

Some thoughts on how to deal with this?

Best regards

Hello,

I’m having the same problem with an example I’ve submitted to the yii playground project; you can see the source here: http://www.yiiplayground.cubedwater.com/index.php?r=UiModule/dataview/gridViewArray

As you can see I had to comment the sort parameters or else I’d get the same error you reported ::)

bye,

Giovanni.

Oh, i now see that there is a ticket created already: http://code.google.com/p/yii/issues/detail?id=1653

It’s from Oct 06, 2010 - so i must have overlooked it. Sorry!

Regards