php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #44807 Calling parent::__set when __set is overloaded = parent->child->parent calls
Submitted: 2008-04-23 14:09 UTC Modified: 2008-07-21 12:21 UTC
From: agostone at freemail dot hu Assigned: colder (profile)
Status: Not a bug Package: Scripting Engine problem
PHP Version: 5.2CVS-2008-04-24 OS:
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: agostone at freemail dot hu
New email:
PHP Version: OS:

 

 [2008-04-23 14:09 UTC] agostone at freemail dot hu
Description:
------------
If i have an overloaded __set function in a class and call parent::__set from another function, the parent calls the child's __set back and a loop gets created like this:

parent::__set (initial call)
child::_set
parent::_set

I need __set function to do some prefixing by default when assigning new string properties by default, i need a custom function to assign un-prefixed properties too, if there is a need (will happen very rarely)... I need this to auto prefix string variables passed to my view object (they gotta be passed as object properties), the MVC framework is a 3rd party framework, i'm extending it's view object and i don't want to modify the original source...

Reproduce code:
---------------
<?php 

class A
{
	public function __set($pKey, $pValue)
	{
		echo("Class: ".get_class()."| Passed Value:".$pValue."<BR>");
		$this->$pKey = $pValue;
		return true;
	}
}

class B extends A
{
	function setRaw($pKey, $pValue)
	{
		parent::__set($pKey, $pValue);
	}

	function __set($pKey, $pValue)
	{
		echo("Class: ".get_class()."| Passed Value:".$pValue."<BR>");
		$pValue = $this->prefix($pValue);
		parent::__set($pKey, $pValue);
	}

	function prefix($pValue)
	{
		if(is_string($pValue))
		{
			return "(prefixed) ".$pValue;
		}
		return $pValue;
	}
}

$b = new B();

echo("Calling: setRaw()<br>");
$b->setRaw("raw", "shouldn't be prefixed");
echo("<br>");

echo("Calling: __set()<br>");
$b->prefixed = "should be prefixed";

echo("<br>Variable after setraw: ".$b->raw);
echo("<br>Variable after set: ".$b->prefixed);
echo("<br>");

?>

Expected result:
----------------
Calling: setRaw()
Class: A| Passed Value:shouldn't be prefixed

Calling: __set()
Class: B| Passed Value:should be prefixed
Class: A| Passed Value:(prefixed) should be prefixed

Variable after setRaw: shouldn't be prefixed
Variable after set: (prefixed) should be prefixed


Actual result:
--------------
Calling: setRaw()
Class: A| Passed Value:shouldn't be prefixed
Class: B| Passed Value:shouldn't be prefixed
Class: A| Passed Value:(prefixed) shouldn't be prefixed

Calling: __set()
Class: B| Passed Value:should be prefixed
Class: A| Passed Value:(prefixed) should be prefixed

Variable after setraw: (prefixed) shouldn't be prefixed
Variable after set: (prefixed) should be prefixed


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-04-24 21:57 UTC] agostone at freemail dot hu
I've deleted my php installation, kept only php.ini.

downloaded and installed php from this location it:

http://snaps.php.net/win32/php5.2-win32-latest.zip

Executed the code, here are the results:
Calling: setRaw()
Class: A| Passed Value:shouldn't be prefixed
Class: B| Passed Value:shouldn't be prefixed
Class: A| Passed Value:(prefixed) shouldn't be prefixed

Calling: __set()
Class: B| Passed Value:should be prefixed
Class: A| Passed Value:(prefixed) should be prefixed

Variable after setraw: (prefixed) shouldn't be prefixed
Variable after set: (prefixed) should be prefixed

Seems it still exists.
 [2008-04-24 22:18 UTC] colder@php.net
This is "expected", the recursion protection that allows you to dynamically create properties inside __set is not enabled before the first __set called via overloading.

Example:

class A {
    public function __set($n, $v) {
        echo "Setting $n = $v\n";
        $this->$n = $v;
    }
}

$a = new A;
$a->k1 = "v1";

$a->__set("k2", "v2");

Will end up outputting:
Setting k1 = v1
Setting k2 = v2
Setting k2 = v2

because the recursion protection isn't there when you do a manual call to __set().
 [2008-04-25 08:16 UTC] agostone at freemail dot hu
I happen to experience this problem with magic functions only, i understand what You wrote, still, the question is there... May i hope that You guys will put this "expected" behavior into the bug fix chain or should i accept the fact that it won't get fixed ever?
 [2008-07-21 12:17 UTC] pajoye@php.net
Not os specific, assign to Etienne for now.
 [2008-07-21 12:21 UTC] colder@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

It won't get fixed, as a fix would require a method name comparison for each and every method calls. It's not worth it.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 14:01:29 2024 UTC