Jump to content

private variables/scope conflict?


thescientist

Recommended Posts

so the other day I was stumped trying to implement usort, using a simple custom function, wherein I needed the comparison key to be dynamic. Basically I was sorting a bunch of sport stats and needed to sort the stats according to a specific mapping that was being passed into my class (in order to maintain integrity with javacript functionality for showing hiding the stats based on a link being clicked on the page). Given that the class has been instantiated, and we are calling the render method, this is what wasn't working...

class LeadersTabContentRenderer{	  private $leaders;   private $leadersMap;  private $sportId;  private $leadersByStat = array();  private $currentStat = '';  function __construct($leaders, $leadersMap, $sportId){	$this->leaders = $leaders;	$this->leadersMap = $leadersMap;	$this->sportId = $sportId;  }	  private function sortStats($a, $b){	if ($a[$this->currentStat] == $b[$this->currentStat]) {	  return 0;	};	return ($a[$this->currentStat] > $b[$this->currentStat]) ? -1 : 1;  }    private function render(){	$output = '';	$temp = array();	$output .= '<ul class="tabs"> ';	foreach($this->leadersMap as $key => $value){	  $output .= '<li><a href="" class="stat" name="' . $key . '">' . $value . '</a></li>';	  $this->currentStat = $key;	  $temp = $this->leaders;	  usort($temp, sortStats);	  $this->leadersByStat[$key] = $temp;	};	$output .= '</ul> ';		return $output;  }}

basically the output was fine, as far as the page was concerned, but nothing was being sorted. I couldn't figure out why it wasn't working. I had implemented usort in another application where the sorting key was known, and the data structure was the same as this one; $leadersMap is a numeric array of associative arrays. When I hardcoded the key in the sort function, it would work. i.e.

if ($a['bbasst'] == $b['bbasst']) {  return 0;};return ($a['bbasst'] > $b['bbasst']) ? -1 : 1;

eventually I got it working using something I found online, making the sort function accept the field for sorting, and changing the render function

private function orderStatsBy($data, $field){  $code = "return strnatcmp(\$a['$field'], \$b['$field']);";  usort($data, create_function('$a,$b', $code));  return array_reverse($data);}..$menu .= '<ul class="tabs"> ';foreach($this->leadersMap as $key => $value){  $menu .= '<li><a href="" class="stat" name="' . $key . '">' . $value . '</a></li>';  $this->leadersByStat[$key] = $this->orderStatsBy($this->leaders, $key); }; $menu .= '</ul> ';

so two questions (hopefully I didn't leave anything critical out in the code basic code snippets, having written this after committing my completed work): 1) any reason why in the above contect $this->currentStat wasn't being interpreted correctly (or in a way I thought would/should have worked), while a hardcoded value would have? a conflict of scope?2) is the implementation of orderByStats good? I have to admit, I found it online, so I don't want to use something that promotes bad practices, and it kind of feels like's it written using the eval() of PHP.

Link to comment
Share on other sites

1) any reason why in the above contect $this->currentStat wasn't being interpreted correctly (or in a way I thought would/should have worked), while a hardcoded value would have? a conflict of scope?
Right. First, function references in PHP are not like Javascript. You can't simply use the function name without parentheses. In PHP you pass the function name as a string. Second, there's no function called sortStats. There's a method called sortStats in the class, but that's not what you're telling it to use, you're telling it to use a global function. If you want to call a method of the object you pass the object reference, then the method name as a string, in an array:usort($temp, array($this, 'sortStats')); // sort with $this->sortStats as the comparison functionLooks a little weird, especially if you're used to Javascript, but that's how PHP does it.
is the implementation of orderByStats good? I have to admit, I found it online, so I don't want to use something that promotes bad practices, and it kind of feels like's it written using the eval() of PHP.
It's not so much like eval as it is like an anonymous function in Javascript. In previous versions of PHP you have to use create_function to create an anonymous function. In recent versions you can actually just create an anonymous function the same way you would in Javascript. With PHP 5.3+ you can do this instead:http://www.php.net/manual/en/functions.anonymous.php
Link to comment
Share on other sites

I see. I tried with the quotations around 'sortStats' but that didn't work either, but apparently it wouldn't have worked that way anyway, as you say it was looking for a global function called sort stats. I thought I had tried $this->sortStats/'$this->sortStats' but those probably wouldn't have worked either I'm guessing; if I passed '$this->sortStats' would it have actually looked in the global scope for a function literally called $this->sortStats?as for your explanation

usort($temp, array($this, 'sortStats')); // sort with $this->sortStats as the comparison function

would that be similar in nature to using apply() from Javascript?Thanks for the link, seems like I would like to be able to use that my advantage more often.p.s. now that you have enlightened me on the scoping issue I was having, I can see know why my previous use of usort in my other application worked, as that was without any context of a class.thanks very much for your time! :)

Link to comment
Share on other sites

if I passed '$this->sortStats' would it have actually looked in the global scope for a function literally called $this->sortStats?
No, it would have looked for a method, but $this would not have been set to your object instance because of the scope in which the string gets evaluated. So the alternative is to actually pass the object instance itself, and then the method name as a string in the array like I showed. An example of doing that is also on the manual page for usort.
would that be similar in nature to using apply() from Javascript?
Sort of, at least in the sense that you're passing a scope to it.
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...