php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #29767 Weird behaviour of __set($name, $value);
Submitted: 2004-08-20 03:55 UTC Modified: 2005-02-02 08:20 UTC
Votes:2
Avg. Score:3.5 ± 1.5
Reproduced:1 of 2 (50.0%)
Same Version:0 (0.0%)
Same OS:1 (100.0%)
From: morten at nilsen dot com Assigned: dmitry
Status: Closed Package: Scripting Engine problem
PHP Version: 5.0.1 OS: Linux
Private report: No CVE-ID:
 [2004-08-20 03:55 UTC] morten at nilsen dot com
Description:
------------
The attached script behaves ilogically


Reproduce code:
---------------
<?php
  class template {
    function __set($name, $value) {
      echo "Set $name to $value<br>";
      if($name[0] != '&') $name = '&'.$name.';';
    }
  }

  function fetchlist($name) {
    global $template;

    echo '$template->what = '.$name.'<br>';
    $template->what = $name;

  } 

  $template = new template();
  fetchlist('user');
  fetchlist('group');
?>

Expected result:
----------------
$template->what = user
Set what to user
$template->what = group
Set what to group

Actual result:
--------------
$template->what = user
Set what to user
$template->what = group
Set &what; to group

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-08-20 04:16 UTC] morten at nilsen dot com
(obvious) workaround is to change:

  if($name[0] != '&') $name = '&'.$name.';';

into:

  $entity = "&$name;";
 [2004-08-20 04:52 UTC] morten at nilsen dot com
further weirdness uncovered with this code;

<?php
  class test {
    function __set($name, $value) {
      $name = $name.$value;
      echo "$name<br>";
    }
  }

  $test = new test;
  $test->kake = 1;
  $test->kake = 2;
  $a = 3;
  $test->kake = $a;
  $a++;
  $test->kake = $a;
  for($a = 0; $a < 10; ++$a)
    $test->kake = $a;
?>
 [2005-01-25 20:55 UTC] eric-php at famderuiter dot net
This problem can also be seen in __get

test case:
---------------------

<?php

class Test {

  private $group_id = 1;
  private $group_name = 'test_group';

  public function __get($name) {
    echo "get $name called\n";
    $name = 'group_' . $name;
    return $this->$name;
  }

  public function __set($name, $value) {
    echo "set $name, $value called\n";
    $name = 'group_' . $name;
    $this->$name = $value;
  }
}

$test = new Test();
for ($i=0; $i<2; $i++) {
  echo $test->name . "\n";
  $test->name = $i;
}

?>

Output:
----------------------
get name called
test_group
set name, 0 called

Fatal error:  Cannot access private property Test::$group_name in /var/www/AAF/bug.php on line 23

Expected Output:
-----------------------
get name called
test_group
set name, 0 called
get name called
0
set name, 1 called

What is happening here?
-------------------------
It looks like the 'name' argument in both __get and __set is passed by reference. 
Clearly this should not be happening because it allows code morphing and the error messages are very confusing (eg: Cannot access private property Test::$group_name in /var/www/AAF/bug.php on line 23 <= there is no reference to $group_name on that line .. only to name .. took me a while to figure out what was wrong)
 [2005-02-02 08:20 UTC] dmitry@php.net
Fixed in CVS (HEAD and PHP_5_0).
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 20:01:57 2014 UTC