php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #47384 static references resolved incorrectly with class inheritance
Submitted: 2009-02-13 22:55 UTC Modified: 2010-01-11 00:15 UTC
From: alreece45 at gmail dot com Assigned:
Status: Not a bug Package: Documentation problem
PHP Version: 5.*, 6 OS: *
Private report: No CVE-ID: None
 [2009-02-13 22:55 UTC] alreece45 at gmail dot com
Description:
------------
When defining properties using constants with parent or self, they are resolved using computed classes instead of defined classes.

This behavior appears to have existed since PHP 5.0.5 and still exists in PHP 5.3beta3, a 5.3 CVS snapshot (200902122000), and 5.2 CVS snapshot (200902121200).

Someone has brought this up before in php-internals:
http://marc.info/?l=php-internals&m=118839969729862&w=2

Reproduce code:
---------------
<?php
	class Father {
		const my_name = 'Father';
		public $name = self::my_name;
	}
	class Son extends Father {
		const my_name = 'Son';
		public $daddy = parent::my_name;
	}
	class GrandSon extends Son {
		const my_name = 'Grandchild';
	}

	$older = new GrandSon;
	echo "{$older->name}\n";
	echo "{$older->daddy}\n";
?>

Expected result:
----------------
Father
Father

Actual result:
--------------
Grandchild
Son

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-14 13:51 UTC] alreece45 at gmail dot com
Perhaps this is not a Documentation Problem, but a scripting problem? I set it as documentation because I wasn't sure if this behavior was intentional or not. If it was intentional, the documentation needed to be updated because it currently says:

"Static references to the current class like self:: or __CLASS__ are resolved using the class in which the function belongs, as in where it was defined"

I'd appreciate it to know, at the very least, if this behavior is intentional or not for two reasons:
1) Avoid using the "feature" in PHP projects.
2) So I know if I take the time to try make a patch: I know I didn't just waste my time (even if I fail).

also: updating the summary to be more clear (hopefully)
 [2009-06-14 23:09 UTC] scottmac@php.net
You can use static:: in PHP 5.3+ this is Late Static Binding.
 [2009-06-15 14:57 UTC] alreece45 at gmail dot com
In the example self is behaving as static does. It should not be doing that. It contradicts the documentation.

In the father class: $name is set as self::my_name, which is "Father". In the child classes, even though $name is not set, it goes to Son::my_name and GrandSon::my_name.
 [2009-11-20 10:01 UTC] vrana@php.net
Difference between self:: and static:: is already documented.
 [2009-11-20 13:40 UTC] alreece45 at gmail dot com
Again, this is NOT the difference between self and static, this is the 
self keyword behaving like static when it shouldn't.
 [2009-11-23 14:54 UTC] vrana@php.net
If the variable is initialized in the constructor then it gives the expected output:

function __construct() {
	$this->name = self::my_name;
}

So this is specific to initialization in the declaration.
 [2010-01-10 13:37 UTC] degeberg@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

This is expected behavior. Note that there is a difference between class constants and static class properties. Regular, non-static properties are set when an object is constructed.

Upon construction of a GrandSon object, self::my_name would 'Grandchild' and parent::my_name would contain 'Son'. You can achieve the kind of behavior you're looking for using static properties:

<?php
class Father {
	public static $my_name = 'Father';
	public $name;
	
	public function __construct() {
		$this->name = self::$my_name;
	}
}
class Son extends Father {
	static $my_name = 'Son';
	public $daddy;
	
	public function __construct() {
		parent::__construct();
		$this->daddy = parent::$my_name;
	}
}
class GrandSon extends Son {
	static $my_name = 'Grandchild';
}

$older = new GrandSon;
echo "{$older->name}\n";
echo "{$older->daddy}\n";
?>
 [2010-01-10 19:35 UTC] alreece45 at gmail dot com
Again, not bogus, the value of the property $name depends on the order 
the objects are created. 

Even if the expected behavior makes late static binding possible with 
the self keyword instead of the static keyword. That use is not yet 
documented, and then the following would become unexpected as it now 
displays "Father, Father" both times (instead of "Son, Grandson" when 
an instance of Father is not made). 

The value of the property should not depend on the order of the 
objects initiated.

New Reproduce Code (Does not replace the previous test script, the 
original test script output is still the same, and the bug still 
holds):

<?php
	class Father {
		const my_name = 'Father';
		public $name = self::my_name;
	}
	class Son extends Father {
		const my_name = 'Son';
		public $daddy = parent::my_name;
	}
	class GrandSon extends Son {
		const my_name = 'Grandchild';
	}
	$temp = new Father;
	$older = new GrandSon;
	echo "{$older->name}\n"; // outputs Father
	echo "{$older->daddy}\n"; // outputs Father
?>
 [2010-01-10 21:36 UTC] degeberg@php.net
Using PHP 5.3.1, I get "Grandson" then "Child" regardless of the $temp object's presence.

I think you're confusing class constants (http://php.net/oop5.constants) with static properties (http://php.net/oop5.static). Despite similar syntax for accessing them, they do not behave the same way.

Static properties are bound to the defining class. Regular (non-static) properties are bound to the object. Seeing as the object does not exist prior to its instantiation, the value is not bound before that happens.
 [2010-01-11 00:15 UTC] alreece45 at gmail dot com
I understand your point with static properties, however:

A) because the $name property is defined in Father, it should be using 
the "self" as seen from Father (as happens when you use the constant 
from a method like __construct). If this is not the expected case, the 
documentation should be clarified that using self changes depending on 
the context. 

The following code should ALWAYS set the property to the same value 
when defined in the same class (regardless of child classes).

1)  public $var = self::someConstant;
2) 
  function __construct() {
    $this->var = self::someConstant;
  }

B) Because both class constants and static properties and methods are 
tied to a class definition. It should be documented with class 
constants whether or not they are static.

C) I incorrectly concluded when writing the test case that the object 
instance affected non-static properties (I encountered the bug in a 
more complex code-base). However, it does affect the values when  
static properties are used (another example included below).

<?php
       class Father {
               const my_name = 'Father';
               public static $name = self::my_name;
       }
       class Son extends Father {
               const my_name = 'Son';
               public static $daddy = parent::my_name;
       }
       class GrandSon extends Son {
               const my_name = 'Grandchild';
       }
       // new Father(); // uncommenting this line affects output
       echo Grandson::$name  . "\n"; // outputs Grandchild
       echo Grandson::$daddy . "\n"; // outputs Son
 
?>
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Mon Jul 14 12:01:33 2025 UTC