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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
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: Wed Dec 11 12:01:29 2024 UTC