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
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: landers dot robert at gmail dot com
New email:
PHP Version: OS:

 

 [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: Sun Dec 22 02:01:28 2024 UTC