parent

用户可能会发现自己写的代码访问了基类的变量和函数。如果派生类非常精炼或者基类非常专业化的时候尤其是这样。

不要用代码中基类文字上的名字,应该用特殊的名字 parent,它指的就是派生类在 extends 声明中所指的基类的名字。这样做可以避免在多个地方使用基类的名字。如果继承树在实现的过程中要修改,只要简单地修改类中 extends 声明的部分。

<?php
class {
    function 
example() {
        echo 
"I am A::example() and provide basic functionality.<br />\n";
    }
}

class 
extends {
    function 
example() {
        echo 
"I am B::example() and provide additional functionality.<br />\n";
        
parent::example();
    }
}

$b = new B;

// 这将调用 B::example(),而它会去调用 A::example()。
$b->example();
?>
add a note add a note

User Contributed Notes 30 notes

up
38
ckrack at i-z dot de
20 years ago
Note that we can use $this in the parent's method like we might expect.
It will be used as the instance of the extended class.

<?php
class foo {
    var
$x;
    function
foofoo()
    {
       
$this->x = "foofoo";
        return;
    }
}
class
bar extends foo {
   
// we have var $x; from the parent already here.
   
function barbar()
    {
       
parent::foofoo();
        echo
$this->x;
    }
}
$b = new bar;
$b->barbar(); // prints: "foofoo"
?>
up
26
pjm at pehjota dot com
15 years ago
I've seen people in the comments below use this, but I've also seen some unecessary workarounds to achieve it. So I thought I'd clarify, even though it is shown in the documentation. You CAN reference non-static parent methods, as in other languages. For example...

<?php

abstract class ParentClass {
    public function
doSomething() {
        echo
"done.\n";
    }
}

class
ChildClass extends ParentClass {
    public function
doSomething() {
        echo
"attempting something.\n";
       
parent::doSomething();
    }
}

$obj = new ChildClass();
$obj->doSomething();

?>

This will output both "attempting something." and "done." As you might expect, it also works if the parent method is protected. Users of other languages may have tried defining static and non-static methods with the same name. This is why that doesn't work ("parent" can refer to both static and non-static methods, and there's no way to differentiate them).

However, you CANNOT use the "parent" keyword to reference the parent's variables. When in a class, "parent" will always look for static variables. For example, this results in an "Access to undeclared static property" fatal error:

<?php

abstract class ParentClass {
    public
$var = 5;
}

class
ChildClass extends ParentClass {
    public function
setVar($val) {
       
parent::$var = $val;
    }
    public function
getVar() {
        return
parent::$var;
    }
}

$obj = new ChildClass();
$obj->setVar(6);  // Results in fatal error.
echo $obj->getVar() . "\n"// Results in fatal error.
echo $obj->var . "\n"// Would work and reference the parent's $var unless the child has its own $var.

?>
up
2
matirank at hotmail dot com
9 years ago
class ExtendClass
{
     public function __construct($variable,$array){
         return null;
     }
}

class NameClass extends ExtendClass
{
    public function __construct($variable=null,$array = array()) {
        parent::__construct($variable, $array);
    }
}
up
2
greg-wilson at hotmail dot com
12 years ago
You can access/modify variables of the parent class from multiple subclasses:

class Superclass{
    private static $arr = array();
   
    protected addArrayElement($element){
        self::$arr[] = $element;
    }

    protected printArray(){
        var_dump( self::$arr );
    }
}

class SubclassA extends Superclass{
    public function addToArray($elem){
        parent::addArrayElement($elem);
    }
}

class SubclassB extends Superclass{
    public function addToSameArray($elem){
        parent::addArrayElement($elem);
    }
}

$classA = new SubclassA;
$classA->addToArray("first");
$classB = new SubclassB;
$classB->addToSameArray("second");

calling '$classB->printArray()' results in both "first" and "second" being printed, demonstrating shared static access to a superclass variable from multiple extended classes.
up
1
lesion at autistici dot org
15 years ago
take care of using parent::method with not declared method when using __call because in this case the string method will be lowercase:

<?php
class A {
    function
__call( $method, $args ) {
      echo
get_class( $this )  . ' ' . $method . "\n";
    }
}

class
B extends A {
    function
getTest() {
       
parent::getTest();
    }
}

$a = new A();
$a->getTest();
$b = new B();
$b->getTest();

?>

output:

A getTest
B gettest
up
1
johnremovethreewordsplatte at pobox dot com
22 years ago
Combining the above suggestions with the "Pull Up Constructor Body" refactoring from Fowler (http://www.refactoring.com/catalog/pullUpConstructorBody.html), I found an elegant way to inherit constructors in PHP. Both superclass and subclass constructors call an initialize() method, which can be inherited or overridden. For simple cases (which almost all of mine are), no calls to parent::anything are necessary using this technique. The resulting code is easy to read and understand:

class Superclass {
    function Superclass($arg) {
        $this->initialize($arg);
    }
    function initialize($arg) {
        $this->setArg($arg);
    }
}

class Subclass extends Superclass {
    function Subclass($arg) {
        //initialize() is inherited:
        $this->initialize($arg);
    }
}
up
0
KOmaSHOOTER at gmx dot de
19 years ago
An example for using a memberfunction with another memberfunction.

The sequencing for the creating of the class is important.

<?php
class A
{
   function
example()
   {
       echo
"I am A::example() and provide basic functionality.<br>\n";
   }
}

class
B extends A
{
   function
example()
   {
       echo
"I am B::example() and provide additional functionality.<br>\n";
      
parent::example();
   }
}

class
C extends A
{
  
   function
example()
   {
          global
$b;
       echo
"I am c::example() and provide additional functionality.<br>\n";
      
parent::example();
      
$b->example();
   }
}
$b = new B();
$c = new C();
$c->example();
;
?>

Result:

I am c::example() and provide additional functionality.
I am A::example() and provide basic functionality.
I am B::example() and provide additional functionality.
I am A::example() and provide basic functionality.
up
-1
nate at 8
16 years ago
To simulate traditional C# like parent access, child classes can be defined in the parent's constructor and linked via explict definition. ($this->b->par = $this;)

<?php
class A {

  var
$foo;
  var
$b;

  function
A(){
   
$this->foo = "foo!";
   
$this->b = new B;
   
$this->b->par = $this;
    }
   
  function
bar(){
    print(
"bar!");
    }
   
};

class
B {

  var
$par;

  function
B(){
    }
   
  function
bar(){
    print(
$this->par->foo );
   
$this->par->bar();
    }
   
};

$test = new A;
$test->b->bar();
?>

This returns:

foo!bar!

demonstrating both variable and function access via the parent.
up
0
Anonymous
20 years ago
About the constructors :

Yes, a good pratrice could be to use a method called by the real constructor. In PHP 5, constructor are unified with the special __construct method. So we could do :

<?php
class A {
    var
$a = "null";
    function
A() {
       
$args = func_get_args();
       
call_user_func_array(array(&$this, "__construct"), $args);
    }
    function
__construct($a) {
       
$this->a = $a;
        echo
"A <br/>";
    }
}

class
B extends A {
    var
$b = "null";

    function
__construct($a, $b) {
       
$this->b = $b;
        echo
"B <br/>";
       
parent::__construct($a);
    }
    function
display() {
        echo
$this->a, " / ", $this->b, "<br/>";
    }
}

$b = new B("haha", "bobo");
$b->display();

?>

It will have the same behavior than standard php constructors, except that you can not pass arguments by reference.
up
0
mazsolt at yahoo dot com
21 years ago
There is a difference between PHP and C# managing the overloaded variables of the parent class:

<?php
class a{
var
$a=1;
function
display(){
echo
$this->a;
}
}

class
b extends a{
var
$a=9;
}

$x=new b;
$x->display(); // will display 9
?>

The same code in C# will display the value from the parent class.

[C#]
class a{
private int a=1;
public int display(){
return this.a;
}
}

class b:a{
private int a=9;
}

b x = new b();
Response.Write(b.display()); // will display 1
up
0
lelegiuly at iol dot it
21 years ago
Sorry but my example above it's correct only if there's one class that inherits by another class. If the hierarchical tree is deeper than 2 my example doesn't work. The result is a infinite loop cycle.
Why? Because the only instanced object is the B class (in my example).

$this alwais refer to instanced object.

See also the "sal at stodge dot org" notes in 4 October 2002.
up
0
lelegiuly at iol dot it
21 years ago
If you like Java and you have to call parent constructor, this is my method:

class object {
   function super() {
     $par = get_parent_class($this);
     $this->$par();
   }
}
class A extends object {
   function A() {
     echo "A constructor\n";
   }
}
class B extends A {
   function B() {
     $this->super();
     echo "B constructor\n";
   }
}

Include the classes above, instance a new B class and this is the output:

A constructor

B constructor

In your web application every class will extend the object class.
Good luck, Emanuele :)
up
0
aid at logic dot org dot uk
21 years ago
With regard to the chaining of Constrcutures, surely this is a simple and replaible method..?

<?php
class A
 
{
  function
A()
    {
    print
"Constructor A<br>\n" ;
    }
  }
 
class
B extends A
 
{
  function
B()
    {
   
parent::A () ;
    print
"Constructor B<br>\n" ;
    }
  }

class
C extends B
 
{
  function
C()
    {
   
parent::B ();
    print
"Constructor C<br>\n" ;
    }
  }
 
$o = new C;
?>
Which outputs,

Constructor A
Constructor B
Constructor C
up
0
mwwaygoo at hotmail dot com
22 years ago
With the example given previous from johnremovethreewordsplatte@pobox.com

You should only do this if your initialisation is different (no point in extending if it isn't)

When you extend a class its constructor still remains valid and is executed when constructed.  Writing a new constructor in the extended class overwrites the old one - inheritance.

so the following will also work

class Superclass {
function Superclass($arg) {
$this->initialize($arg);
}
function initialize($arg) {
$this->setArg($arg);
}
}

class Subclass extends Superclass {
//initialize() is inherited:
//BUT so is constructor

function extra_stuff($arg) {
echo "extra stuff " . $arg;

}
}

THE constructor is the function who's name is the same as the class that it is defined within.
AND remains the constructor even in extended classes, until redefined.

Think of the constructor as a seperate function from all the others.  As if PHP looks at your class and makes a copy of the function of the same name as the class and calls it "Constructor".

You can also create a function within the extended class with the same name as the constructor in the parent class without re-writing the constructor.  Because you are not altering the "Constructor" function.
(BUT any redefined variables are used in the constructor, as expected)

ie
class One
{
  var $v = "one";

  function One()
  {
    print "Class One::Constructor value=" . $this->v . "<br />\n";
  }
}

class Two extends One
{
  var $v = "two";

  function one()
  {
    print "REDEFINED : Class Two::Function One value=" . $this->v . "<br />\n";
  }
}

$o = new One();
$o->one();
$p = new Two();
$p->one();

results in :-
Class One::Constructor value=one
Class One::Constructor value=one
Class One::Constructor value=two
REDEFINED : Class Two::Function One value=two
up
0
gibby at onebox dot com
22 years ago
Regarding the example above, I believe the result is misleading, if you're inferring that the $this in Class One's OneDo method refers to One.

If that wasn't your conclusion, then my apologies-- I misunderstood you.

But if it was, it might save trouble to note that $this is effectively an alias for $o (a Class Two object).  $v is available to $o, and that's how it's being picked up.  $this is $o in that example, not One (One is a class and has no implementation).

I hope that's helpful.

Brad
up
0
seedpod23 at hotmail dot com
22 years ago
This example might illustrate something which was unclear to me when using the $parent::method() syntax.

I didn't see any documentation on whether or not $this (object variables) would be available in the parent class method so I wrote this example:

class One {

  var $v = "one";

  function OneDo() {
    print "One::OneDo " . $this->v . "<br>\n";
  }
}

class Two extends One {

  function CallParent() {
    parent::OneDo();
  }
}

$o = new Two();

$o->CallParent();

The output is "One::OneDo one", happy day!
up
-1
sal at stodge dot org
22 years ago
<p>When using the technique suggested by "<b>minoc at mindspring dot com</b>" on this page - USE EXTREME CAUTION.</p>

The problem is that if you inherit of a class that uses this kludge in the constructor you will end up with a recursive constructor - unless that new class has a constructor of it's own that by-passes the kludged constructor.

What I am saying, is you can use this technique as long as you can ensure that each class you inherit from a class containing this technique in the constructor has a constructor class of it's own that does not call the parent constructor...

On balance it is probably easier to specify the name of the constructor class explicitly!

If you make this mistake the symptoms are pretty easy to spot - PHP spirals into an infinitely recursive loop as soon as you attempt to construct a new class. Your web-server will returns an empty document.
up
-1
php at earthside dot arg
22 years ago
Here is the workaround I came up with based on the comments about using a 'constructor' method and the parent:: syntax...

#cat test.php
<?php
class foo {
  function
foo() { $this->constructor(); }
  function
constructor() {
    echo
get_class($this)." (foo)\n";
  }
}
class
bar extends foo {
  function
bar() { $this->constructor(); }
  function
constructor() {
    echo
get_class($this)." (bar)\n";
   
parent::constructor();
  }
}
class
baz extends bar {
  function &
baz() { $this->constructor(); }
  function &
constructor() {
    echo
get_class($this)." (baz)\n";
   
parent::constructor();
  }
}
$o = new baz;
?>
#php test.php
X-Powered-By: PHP/4.1.2
Content-type: text/html

baz (baz)
baz (bar)
baz (foo)
#

--
'a' -> 'o' in email TLD
up
-1
tim dot parkinson at ntlworld dot com
23 years ago
There is an implication here that variables of the parent class are available.  You can't access variables using parent::
up
-2
bitmore.co.kr
20 years ago
/* Original */
/*
class A {
    var $x;
    function A() { $this->x = 32; }
    function joke() { print "A::joke" . A::x . "<br>\n"; # SYNTAX ERROR!! }
}
class B extends A {
    var $x;
    function B() {
        parent::A();
        $this->x = 44;
    }
    function joke() {
        parent::joke();
        print "B::joke " . $this->x . "<br>\n";
    }
}
echo A::joke();
echo B::joke();
*/

/* Original */
/* Modify */
/*
class A {
    var $x;
    function A() { $this->x = 32; }
    function joke() {
        $this = new A;
        print "A::joke = " . $this->x . "<br>\n";
    }
}
class B extends A {
    var $x;
    function B() {
        parent::A();
        $this->x = 44;
    }
    function joke() {
        parent::joke();
        $this = new B;
        print "B::joke = " . $this->x . "<br>\n";
    }
}

echo A::joke();
echo B::joke();

//print Show
A::joke = 32
A::joke = 32
B::joke = 44
*/
up
-2
adrian dabrowski
21 years ago
if you like to use the here suggested method of calling a parent constructer by using get_parent_class(), you will expirience undesired behaviour, if your parent is using the same technique.

class A {
  function A() {
     $me = get_class($this);
     echo "A:this is $me, I have no parent\n";
  }


class B extends A {
  function B() {
     $par = get_parent_class($this);
     $me = get_class($this);
     echo "B:this is $me, my parent is $par\n";
    
     parent::$par();
  }


class C extends B {
  function C() {
     $par = get_parent_class($this);
     $me = get_class($this);
     echo "C:this is $me, my parent is $par\n";
    
     parent::$par();
  }

new C();

this will not produce the output you probably expected:
C:this is c, my parent is b
B:this is b, my parent is a
A:this is a, i have no parent

...but insted you will get in serious troubles:
C:this is c, my parent is b
B:this is c, my parent is b

Fatal error:  Call to undefined function:  b() in .............. on line 16

$this is always pointing to the 'topmost' class - it seems like this is php's way to cope with polymorphic OOP.
up
-2
hustbaer
21 years ago
something on the note of 'minoc':

in this setup, the "$this->$par();" will lead to infinite recursion...

class foo extends bar {
  function foo() {

    $par = get_parent_class($this);
    $this->$par();

    // then normal constructor stuff.
    // ...
  }

  function bar()
  {
    echo "this makes no sense, but who cares :)";
  }
}

but the problem is easity fixed by going like so:

class foo extends bar {
  function foo() {

    $par = get_parent_class($this);
    parent::$par();

    // then normal constructor stuff.
    // ...
  }

  function bar()
  {
    echo "this makes no sense, but who cares :)";
  }
}
up
-2
Dan
21 years ago
I agree with "anonymous coward". That syntax seems silly in a constructor and only results in an extra function being called. The only time the parent will ever change is if you change the extends expression in your class definition.

However, the parent:: syntax is very useful when you need to add extra functionality to a method of a child class which is already defined in the parent class.

Example:

class foo {
   var $prop;

   function foo($prop = 1) {$this->prop = $prop;}

   function SetProp($prop) {$this->prop = $prop;}
}

class bar extends foo {
   var $lastprop;

   function bar($prop = NULL) {
      is_null($prop) ? $this->foo() : $this->foo($prop);
   }

   function SetProp($prop) {
      $this->lastprop = $this->prop;
      parent::SetProp($prop);
   }
}
up
-2
anonymous at cowards dot com
21 years ago
Um, reading through all the gyrations on getting C++ constructor
semantics from PHP, I am wondering if I am just blindly missing something
when I use:

class A {
    function A () {  echo "A Constructor\n"; }
}

class B extends A {
    function B () { $this->A (); echo "B Constructor\n"; }
}

class C extends B {
    function C () { $this->B (); echo "C Constructor\n"; }
}

$c = new C ();

produces:

A Constructor
B Constructor
C Constructor

I'm new to PHP, but it seems to me that this is simpler and cleaner
than the solutions discussed here, with the only disadvantage being that
when you change the name of your superclass you have to change one
line in your subclass.

What am I missing? Are there advanced PHP-OO considerations that
make this code undesireable??
up
-2
php at stock-consulting dot com
16 years ago
It appears that parent refers to the base class of the subclass in which the method is defined, not the subclass in which the method is exceuted. This behaviour is consistent with other object-oriented languages. PHP's documentation is a bit unclear here, so I had to test it (PHP5.2.6).
up
-2
Anonymous
17 years ago
<?php
   
class A {
      function
X() {
        echo
'y';
      }
    }
   
    class
B extends A{
      function
X() {
        echo
'z';
      }
     
      function
Y() {
        echo
parent::X();
      }
    }
   
    class
C extends B {
      function
Z () {
        echo
parent::Y();
      }
    }

$c = new C();
$c->Z();                  //output is 'y'
?>
up
-4
James Sleeman
20 years ago
It should be noted that when using parent:: you are able to call a method defined within the parent, or any class that the parent is extending.. for example.

<?php
 
class A
 
{
    function
test()
    {
      echo
'Hello ';
    }
  }
 
  class
B extends A
 
{
   
  }
 
  class
C extends B
 
{
    function
test()
    {
     
parent::test();
      echo
'Bobby.';
    }
  }
 
 
$D =& new C();
 
$D->test();
?>

Outputs "Hello Bobby.", the fact that B does not define test() means that A's test() is called, it should also be noted that test() is called in the context of an 'A' class, so if you try and call parent:: in A's test() it will correctly fail.

It's also worth noting that parent:: also works fine in a static method, eg <?php  C::test(); ?> still outputs "Hello Bobby.", and you can even do <?php B::test(); ?> which correctly outputs "Hello ", even though we're calling a static method that lives in an ancestor class!
up
-5
venome at gmx dot net
23 years ago
If you have a complex class hierarchy, I find that it's a good idea to have a function constructor() in every class, and the 'real' php constructor only exists in the absolute base class.

From the basic constructor, you call $this->constructor(). Now descendants simply have to call parent::constructor() in their own constructor, which eliminates complicated parent calls.
up
-9
exmodione at yahoo dot com
10 years ago
I was originally impressed with this language, and I got curious about its object-oriented features so I started applying them - but this whole this/self/parent thing is ridiculously stupid - it's confusing - I've been coding in C++ and C# - PHP's OO sucks!  I also heard from an online source many people who use PHP avoid its OO features. Now I know why.  It's stupid.
up
-5
Aman
9 years ago
We can't use parent:: keyword to access property of the parent class like methods as variables are not overridable as method does

Consider the following code

<?php

class Fish
{
    public
$common_name = 'Name';
}

class
Trout extends Fish
{
    public function
getInfo()
    {
       return
parent::$common_name;
    }
}

$brook_trout = new Trout();
echo
$brook_trout->getInfo();

?>

this will cause following error

Fatal error: Access to undeclared static property: Fish::$common_name

Simply use $this keyword to access both own and parent's variable
To Top