Post subject: Missing Ratings
Former player
Joined: 10/1/2006
Posts: 1102
Location: boot_camp
When I checked the movies on this sites it seemed like every one of them suddenly lost all their ratings - was this an intentional reset or a problem with IE? edit: hmm it seems like when I try to rate a movie it doesn't register.
Borg Collective wrote:
Negotiation is irrelevant. Self-determination is irrelevant. You will be assimilated.
Post subject: Re: Missing Ratings
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
For some inexplicable reason, code that used to work no longer does.
      foreach($result as $movieid => &$ratings)
      {
        $rat = $prio = $count = $c = 0;
        print_r($ratings);
        foreach($ratings as $name => &$data)
        {
          $rat  += $data['value'] * $data['priority'];
          $prio += $data['priority'];
          $result[$movieid][$name] = (float)$data['value'];
          $count += $data['count'];
          ++$c;
        }
        if($prio > 0)
          $result[$movieid]['Average'] = $rat / $prio;
        if($c > 0)
          $result[$movieid]['Count'] = $count / $c;
      }
For some reason, it registers the 'Count' as 0, even though print_r() reveals that the 'count' members in $ratings[] are nonzero. Explicit casts to int/float don't help. EDIT: Hmm, removing the & from &$data made it work again. So why did it stop working when I upgraded PHP, when it worked just perfectly before? What else did break?
Post subject: Re: Missing Ratings
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Bisqwit wrote:
For some inexplicable reason, code that used to work no longer does.
      foreach($result as $movieid => &$ratings)
      {
        $rat = $prio = $count = $c = 0;
        print_r($ratings);
        foreach($ratings as $name => &$data)
        {
          $rat  += $data['value'] * $data['priority'];
          $prio += $data['priority'];
          $result[$movieid][$name] = (float)$data['value'];
          $count += $data['count'];
          ++$c;
        }
        if($prio > 0)
          $result[$movieid]['Average'] = $rat / $prio;
        if($c > 0)
          $result[$movieid]['Count'] = $count / $c;
      }
For some reason, it registers the 'Count' as 0, even though print_r() reveals that the 'count' members in $ratings[] are nonzero. Explicit casts to int/float don't help. EDIT: Hmm, removing the & from &$data made it work again. So why did it stop working when I upgraded PHP, when it worked just perfectly before? What else did break?
It broke because you were setting the array contents to a pointer of $data which doesn't make sense in its own right. If you need help with PHP, I can provide some assistance.
Post subject: Re: Missing Ratings
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
okaygo wrote:
It broke because you were setting the array contents to a pointer of $data
What?
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Sorry Bisqwit, I meant $ratings. When you use ampersand you are referencing a variable to another. Once you initialize a variable using the ampersand it becomes a direct reference to its origin. What you were doing was this $result[$movieid] => null;
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
foreach($array as $key => &$value) Does not assign $array as a reference to $value. It assign $value as a reference to the particular $array element at each iteration of the loop. The only difference to this: foreach($array as $key => $value) is that in the former case, $value is a reference to the item, and in the latter, it is a copy of the item. I use references instead of copies when I don't want to consume resources making copies of stuff. If you understood this right in the first place, I don't understand what your message is supposed to explain.
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Bisqwit wrote:
foreach($array as $key => &$value) Does not assign $array as a reference to $value. It assign $value as a reference to the particular $array element at each iteration of the loop.
This is how I believe you had it set:
&$value = $array[key];

0 = $array[key];
EDIT: Nevermind my second half, I don't believe you're ever supposed to initialize a reference, which is what you were doing. You can not set a memory location equal to a value unless you are doing this. &$value = &$array[key];
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
okaygo wrote:
&$value = $array[key];
No. $value = &$array[key];
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Bisqwit wrote:
okaygo wrote:
&$value = $array[key];
No. $value = &$array[key];
$value = Memory Location; Access Violation -> $value = 0;
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
okaygo wrote:
Bisqwit wrote:
$value = &$array[key];
$value = Memory Location; Access Violation -> $value = 0;
eh?
$array = Array(1 => 'a', 2 => 'b');

$tmp = &$array[2]; // this line corresponds to my previous example
$tmp = 'k';

print_r($array);
This is perfectly valid code, and it outputs: Array(1 => 'a', 2 => 'k')
foreach($array as $key => &$value)
  $value = $key * 5;

print_r($array);
This is also valid code. $value is a reference to the particular array item being looped through. It can be modified it one so chooses; the modifications are directly reflected in the array which it refers to.
Tub
Joined: 6/25/2005
Posts: 1377
you're not even changing the contents of $data, so why do you wish to use the reference? php internally does reference counting + copy on write, using a reference is actually slower in this case. I noticed that using foreach to change an array will often lead to unexpected behaviour, so I stopped doing it altogether, but YMMV. A wild guess: phpaccelerator has some obscure bugs (I once noticed all protected members becoming private after upgrading php), so you might want to test without.
What else did break?
find /webroot/ -name '*.php' -exec grep -Hn 'foreach' {} \; | grep '&'
What?
seconded. This isn't C/C++, you cannot load memory locations into references. And foreach ($array as &$data) is documented syntax. It should work.
m00
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Bisqwit wrote:
okaygo wrote:
Bisqwit wrote:
$value = &$array[key];
$value = Memory Location; Access Violation -> $value = 0;
eh?
My bad, thinking C/++. I referred to the PHP documents, and &$data should be referenced to $ratings, which would best be unset after the loop.
Joined: 5/29/2006
Posts: 138
I'm thinking it could possibly be related to this, but not sure... http://groups.google.com/group/comp.lang.php/msg/bf35784c733ef439
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
anubis wrote:
I'm thinking it could possibly be related to this, but not sure... http://groups.google.com/group/comp.lang.php/msg/bf35784c733ef439
The names of the references used in the foreach loops are only used in that location. i.e. $data is not used outside that inner loop, and $ratings is not used outside that outer loop. It is not spillover reference. Thus, the link is not related to the problem.
Joined: 5/29/2006
Posts: 138
$data is used again though - the next time through the outer loop. I'd try what okaygo said and put an unset($data) after the inner loop. I think it'll work then. EDIT: Also, like Tub said, using references in PHP does not make things any quicker - only use them when you need to.
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Ignore okaygo. He does not have a clue what he's saying. Code like this works just fine -- there is nothing wrong with the syntax in it. It's just that somehow, that particular case above does an error.
$sum = 0;
foreach($array as $key => &$subarray)
{
  foreach($subarray as $key2 => &$value)
    $sum += $value;
}
Adding an unset($value); at any point of the code (before outer foreach begins, before inner begins, after inner completes, after outer completes) does not change how it works.
Tub
Joined: 6/25/2005
Posts: 1377
if you do $data = 'value' it'll write the value to the location the reference points to. if you do $data = & $value (like the foreach does) it'll just point the reference to another location, overwriting nothing. using a reference in foreach is documented syntax, and if unset() is required, then that'd be a pretty serious php bug.
m00
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
yes ignore me, I was confused for the first set of posts, and the last half were guesses. however I don't feel as bad knowing that I'm not the only one confused.
Joined: 5/29/2006
Posts: 138
Hm... I just put together a test script... I think I know what the problem is.
$result = array(
        array(
                'number 1' => array('value' => 1,'count' => 5),
                'number 2' => array('value' => 2,'count' => 3),
                'number 3' => array('value' => 3,'count' => 2),
                'number 4' => array('value' => 4,'count' => 1)
        ),
        array(
                'number 1' => array('value' => 1,'count' => 1),
                'number 2' => array('value' => 2,'count' => 8),
                'number 3' => array('value' => 3,'count' => 4),
                'number 4' => array('value' => 4,'count' => 0)
        ));
foreach($result as $id => &$ratings)
{
        foreach($ratings as $name => &$data)
        {
                $result[$id][$name] = (float)$data['value'];
                print_r($data);
        }
}
The line
$result[$id][$name] = (float)$data['value'];
is the same exact thing as
$data = (float)$data['value'];
which means that $data['count'] doesn't exist - $data is just a number, not an array. edit: I'm guessing at the approximate structure of the $result array - if it's different I could be wrong. edit2: If you moved the $count += ... line up one line, it would probably work fine.
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
anubis wrote:
The line
$result[$id][$name] = (float)$data['value'];
is the same exact thing as
$data = (float)$data['value'];
O_o You are right. I wonder how I overlooked that. And when did I introduce that error? And did it "work" before? Thank you. And thanks to others who tried to (and did) help :)
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
Bisqwit wrote:
anubis wrote:
The line
$result[$id][$name] = (float)$data['value'];
is the same exact thing as
$data = (float)$data['value'];
O_o You are right. I wonder how I overlooked that. And when did I introduce that error? And did it "work" before? Thank you. And thanks to others who tried to (and did) help :)
Meh, I tried... :/
Joined: 5/29/2006
Posts: 138
Bisqwit wrote:
O_o You are right. I wonder how I overlooked that. And when did I introduce that error? And did it "work" before? Thank you. And thanks to others who tried to (and did) help :)
No problem - I was almost about ready to call it a bug in PHP too :p. I can tell you why it worked before, assuming you upgraded from PHP4 to PHP5. In php 4, using a reference in a foreach didn't do anything - PHP would still just copy it over, so it would be the same thing as foreach($ar as $k => $v). At least, that's my understanding of it. The php documents for foreach say that references were allowed starting in PHP 5. edit: it still would be better to not use references if you don't need them - much less confusing behavior with no negative aspects.
Editor, Active player (296)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
I was not upgrading from PHP4 to PHP5. It was from PHP5 minor version X to PHP5 minor version Y. The references in foreach() were not even accepted syntax in PHP4.
Banned User, Former player
Joined: 3/10/2004
Posts: 7698
Location: Finland
Tub wrote:
you're not even changing the contents of $data, so why do you wish to use the reference? php internally does reference counting + copy on write, using a reference is actually slower in this case.
I don't understand how using references could be slower than relying on the copy-on-write mechanism. Granted, I don't know too much about the inner workings of PHP, but my guess is that this is not too much different from how, for example, std::string works in C++. At least in gcc, the std::string implementation uses copy-on-write. However, it's naturally still much faster to pass references to strings instead of string instances. Taking a reference to a string is basically equivalent to assigning one pointer to another (which is most probably what the C++ compiler does internally). Copying a std::string instance to another, even if std::string uses internally copy-on-write, produces much more code: It has to copy the pointer to the data (and possibly some other member variables if it has any), it has to increment the reference count, and when the copy goes out of scope it has to decrement the reference count and see if it became zero. None of this is produced when simply using references instead.
Joined: 6/22/2007
Posts: 181
Location: Eastern Michigan University
You could always set some timestamps, and compare them. I think Tub is referencing the PHP Documentation.