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 this is not your bug, you can add a comment by following this link.
If this is your bug, but 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

Add a Patch

Pull Requests

Add a Pull Request

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: Fri Apr 19 14:01:30 2024 UTC