php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #36214 __get method works properly only when conditional operator is used
Submitted: 2006-01-30 19:34 UTC Modified: 2007-01-10 16:01 UTC
From: pexu at lyseo dot edu dot ouka dot fi Assigned: dmitry (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.1.3-dev OS: Windows XP
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: pexu at lyseo dot edu dot ouka dot fi
New email:
PHP Version: OS:

 

 [2006-01-30 19:34 UTC] pexu at lyseo dot edu dot ouka dot fi
Description:
------------
When both __set and __get are set, conditional operator "?" fails to work when used to return variables from __get when working with arrays.

A normal if .. else clause however works fine. With non-array variables there's no problem, either.

If __set is not used, this bug doesn't seem to appear.

Reproduce code:
---------------
class overload
{
  private $array = array();
  public function __set($key, $value)
  {
    $this->array[$key] = $value;
  }
  public function __get($key)
  {
    return isset($this->array[$key])
             ? $this->array[$key]
             : null;
  }
}

$ol = new overload; $ol->arr = array();
array_push($ol->arr, "element");
var_dump($ol->arr);

Expected result:
----------------
array(1) {
  [0]=>
  string(7) "element"
}

Actual result:
--------------
array(0) {
}

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-01-30 19:43 UTC] johannes@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

You're trying to acces a private property (arr) from 
outside the class. 
 [2006-02-02 14:08 UTC] pexu at lyseo dot edu dot ouka dot fi
Even overload::$array is defined as public variable, actual result remains the same. But if I change conditional operator to normal if .. else clause, problem disappers!

So:
function __get ($key)
{
  if (isset($this->array[$key]))
    return $this->array[$key];
  else
    return null;
}

works just fine. So the actual problem can't be a private property which is accessed outside the class, right?
 [2006-02-02 16:04 UTC] mike@php.net
That it works in the latter case is just a side affect which falls under "undefined behaviour".

You should actually see an error telling you that __get() can't return a reference or that array_push() wants a reference.

IIRC it's fixed in current CVS, could you please try?
Where "fixed" means that an error is generated.

Thanks.
 [2006-02-04 00:01 UTC] pexu at lyseo dot edu dot ouka dot fi
I quickly tried the newest snapshot (20060203, 5.1.3-dev) but  neither error messages were generated nor results were any different from 5.1.2. (Error_reporting was set to E_ALL | E_STRICT and display_errors was turned on. I tried both conditional operator and normal if clause.)

But I guess I can utilize ArrayObject etc. to get the expected result I wanted.
 [2006-02-06 10:32 UTC] dmitry@php.net
This is not a bug. Method __get() returns by value and it's result cannot be passed by reference.
 [2006-02-10 17:42 UTC] pexu at lyseo dot edu dot ouka dot fi
Sure it doesn't return a reference, but why this example still prints "5.1.3-dev This shouldn't work, but why are you seeing this text?"?

<?php
class a
{
  public $cond_oper = false,
         $array     = array();
  public function __set ($key, $value)
  {
    return $this->array[$key] = $value;
  }
  public function __get ($key)
  {
    if ($this->cond_oper)
      return true ? $this->array[$key] : null;
    else
      return $this->array[$key]; // This one works even though it shouldn't!
  }
}
$a = new a; $a->a = array();
$a->a[] = "This shouldn't work, but why are you seeing this text?";
$a->cond_oper = true;
$a->a[] = "Nope, this text won't be displayed (which is ok).";
echo phpversion(), "\n", array_pop($a->a);
?>

If I understood your explanations correctly, $a->a should've been an empty array and I should've seen two error messages telling me that __get method didn't return a reference etc.

PHP snapshot I used was built on Feb 10, 2006 15:30 GMT.
 [2006-11-28 03:24 UTC] pajoye@php.net
Is it the same issue? I suspect it to be the same but I'm unsure about the bogus state. I would like to have a little explanation, just to write a good work around if this is not a bug.

In this example, the first init raises a notice "Indirect modification of overloaded property context::$attachments has no effect" as the second works like a charm.

class context
{
  public $stack = array();

  public function __set($name,$var)
  {
    $this->stack[$name] = $var;return;
  }

  public function __get($name)
  {
    if (!isset($this->stack[$name])) {
      return null;
    }
    return $this->stack[$name];
  }
}

$ctx = new context;
$ctx->comment_preview = array();
$ctx->comment_preview['content'] = '';
$ctx->comment_preview['rawcontent'] = '';
$ctx->comment_preview['name'] = '';
$ctx->comment_preview['mail'] = '';
$ctx->comment_preview['site'] = '';
$ctx->comment_preview['preview'] = false;
$ctx->comment_preview['remember'] = false;
var_dump($ctx);


$comment_preview = array();
$comment_preview['content'] = '';
$comment_preview['rawcontent'] = '';
$comment_preview['name'] = '';
$comment_preview['mail'] = '';
$comment_preview['site'] = '';
$comment_preview['preview'] = false;
$comment_preview['remember'] = false;
$ctx->comment_preview = $comment_preview;
var_dump($ctx);

 [2006-11-28 12:32 UTC] pajoye@php.net
As a confirmation of the reference problem, it works using an object (ArrayObject):
$ctx->comment_preview = new ArrayObject();
$ctx->comment_preview['content'] = '';
$ctx->comment_preview['rawcontent'] = '';
$ctx->comment_preview['name'] = '';
$ctx->comment_preview['mail'] = '';
$ctx->comment_preview['site'] = '';
$ctx->comment_preview['preview'] = false;
$ctx->comment_preview['remember'] = false;
var_dump($ctx);

It is getting rather confusing for the users. The bad point is this specific case is that ArrayObject is disabled with --disable-all... 
 [2007-01-10 16:01 UTC] dmitry@php.net
Fixed in CVS HEAD and PHP_5_2
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 14:01:30 2024 UTC