php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70044 Magic __set(), first parameter "undefined" when passed an array "part"
Submitted: 2015-07-11 07:14 UTC Modified: 2015-07-12 02:34 UTC
From: landers dot robert at gmail dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 7.0.0beta1 OS: Docker/Ubuntu
Private report: No CVE-ID: None
 [2015-07-11 07:14 UTC] landers dot robert at gmail dot com
Description:
------------
After banging my head for a bit, I've discovered that my magic __set wasn't getting called. Magic function not being called, see: https://github.com/WickedMonkeySoftware/appti2ude/commit/80e36c00a440dbe0e1a31ad75c14aee275aeba0a#diff-af625482fd8d321b53c4003a64bc2c7cR173

Test script:
---------------
I've already highlighted the exact function in that link. To reproduce:
git clone git@github.com:WickedMonkeySoftware/appti2ude.git appti2ude
cd appti2ude
composer install (doesn't do anything)
./develop.sh
visit webpage/ip

develop.sh requires docker, you can also just point a vhost at the cloned directory and hit index.php.

Expected result:
----------------
You should see output along the lines of "Set $var" in the output.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-07-11 07:32 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2015-07-11 07:32 UTC] requinix@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a short but complete example script to be able to reproduce
this bug ourselves. 

A proper reproducing script starts with <?php and ends with ?>,
is max. 10-20 lines long and does not require any external 
resources such as databases, etc. If the script requires a 
database to demonstrate the issue, please make sure it creates 
all necessary tables, stored procedures etc.

Please avoid embedding huge scripts into the report.


 [2015-07-12 02:16 UTC] landers dot robert at gmail dot com
Here's a derived example. Looks like __set doesn't like arrays...

<?php
class baseClass {
	var $vars = [];
	function __get($var) {
		echo "got $var<br>";
		var_dump($this->vars[$var]);
	}
	function __set($var, $value) {
		echo "set $var = $value<br>";
		$this->vars[$var] = $value;
		echo "<pre>";
		var_dump($this->vars[$var]);
		echo "</pre><br>";
	}
}

$base = new baseClass();
$base->base_class = [];
$base->base_class['test'] = "hi"; // this doesn't work!
?>

But $var should be set to "something", it doesn't look like it is set to anything useful.
 [2015-07-12 02:23 UTC] landers dot robert at gmail dot com
-Summary: Magic __set not getting called +Summary: Magic __set(), first parameter "undefined" when passed an array "part" -Status: Feedback +Status: Open
 [2015-07-12 02:23 UTC] landers dot robert at gmail dot com
After some further investigation, it looks like the "var name" parameter is not set or unset when called like this. I updated the title to reflect this.
 [2015-07-12 02:33 UTC] requinix@php.net
-Status: Open +Status: Not a bug -Package: Unknown/Other Function +Package: Class/Object related
 [2015-07-12 02:33 UTC] requinix@php.net
http://3v4l.org/5SH8M (3v4l may be having issues though)

Running that code you'll get an array-to-string notice (putting $value in a string), a "set" message, a "got" message, and another notice.

The "set" and "got" messages are obviously supposed to be there, but there will not be a second "set" because you are not trying to set a property of the object. To do so you must actually have a "$base->base_class = ...". Modifying a return value will not trigger it.

The second notice speaks to that point:
>Notice: Indirect modification of overloaded property baseClass::$base_class has
>no effect in %s on line %d
What __get returned was (null because you didn't put a return in there, but if you had returned $this->vars[$value] then it would be) a copy of the "test" array. PHP noticed that you tried to modify this copy and specifically warned you that it would not work.

Make __get() return by-reference so that you modify the "original" array and not a copy. Note this only works for values that can be referenced, like $this->vars[$var], and not for expressions or literal values. Which will not trigger a second __set() either.
 [2015-07-12 02:34 UTC] requinix@php.net
*if you had returned $this->vars[$var]
 [2015-07-13 05:02 UTC] landers dot robert at gmail dot com
:doh: Thanks for that...
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 16:01:28 2024 UTC