构造函数

构造函数是类中的一个特殊函数,当使用 new 操作符创建一个类的实例时,构造函数将会自动调用。当函数与类同名时,这个函数将成为构造函数。如果一个类没有构造函数,则调用基类的构造函数,如果有的话。

<?php
class Auto_Cart extends Cart {
    function
Auto_Cart() {
        
$this->add_item ("10", 1);
    }
}
?>

上文定义了一个 Auto_Cart 类,即 Cart 类加上一个构造函数,当每次使用“new”创建一个新的 Auto_Cart 类实例时,构造函数将自动调用并将一件商品的数目初始化为“10”。构造函数可以使用参数,而且这些参数可以是可选的,它们可以使构造函数更加有用。为了依然可以不带参数地使用类,所有构造函数的参数应该提供默认值,使其可选。

<?php
class Constructor_Cart extends Cart {
    function
Constructor_Cart($item = "10", $num = 1) {
        
$this->add_item ($item, $num);
    }
}

// 买些同样的无聊老货
$default_cart = new Constructor_Cart;
// 买些实在货...
$different_cart = new Constructor_Cart("20", 17);
?>

也可以使用 @ 操作符来抑制发生在构造函数中的错误。例如 @new

<?php
class A
{
    function
A()
    {
      echo
"I am the constructor of A.<br>\n";
    }

    function
B()
    {
        echo
"I am a regular function named B in class A.<br>\n";
        echo
"I am not a constructor in A.<br>\n";
    }
}

class
B extends A
{
    function
C()
    {
        echo
"I am a regular function.<br>\n";
    }
}

// 调用 B() 作为构造函数
$b = new B;
?>

类 A 中的函数 B() 将立即成为类 B 中的构造函数,虽然并不是有意如此。PHP 4 并不关心函数是否在类 B 中定义的,或者是否被继承来的。

注意

PHP 4 不会从派生类的构造函数中自动调用基类的构造函数。恰当地逐次调用上一级的构造函数是用户的责任。

析构函数是一种当对象被销毁时,无论使用了 unset() 或者简单的脱离范围,都会被自动调用的函数。PHP 中没有析构函数。可以用 register_shutdown_function() 来替代模拟大多数析构函数的效果。


add a note add a note User Contributed Notes
dexen at NOSPAM dot example dot com
18-Jan-2006 06:44
Destructors aren't supported in PHP, and the sollution of using 'register_shutdown_function()' isn't really suitable for situations when you wan to perform destructor-alike finalization at a PARTICULLAR MOMENT, possibly way before exiting the PHP machine. (or sort of specialized serialization, as it's in my case).

Anyway, the general problem is to PROPAGATE a call through a hierarchy of objects, based on NAME PATTERN, in right ORDER (most_derived-to-most_base). Do not rely on INCLUSION of any CODE in derived classes. Do not assume EXISTENCE of any of 'destruction'  functions. Do support DEEP inheritance.

All i did was to create a _FINI_ function in base class, that calls a 'destructor alike' functions of pattern _%CLASSNAME_. Now, in order to 'destruct' (or serialize) i do  $OBJ->_FINI_(); then i can safely unset ($OBJ), all data is already saved to remote storage.

So, if ExSOMETHING derives from ExSession, which in turn derives from ExObject, i create _ExSOMETHING_ function in class ExSOMETHING and _ExObject_ in class ExObject. Notice there's no _ExSession_, yet nothing breaks.

Code:

<?php
class ExObject {

   function
_FINI_()
   {
      
$p = get_class($this);
       while(
$p ) {
          
$px = '_'.$p.'_';
           if (
method_exists($this, $px) ) {
              
$this->$px();
           }
          
$p = get_parent_class( $p );
       }
   }
}
?>

You may want to create an interface class Destructable, include _FINI_ in it and derive all relevant classes from it.
mark at dreamjunky dot com
30-Jun-2005 12:57
Responding to zax AT email DOT cz and others on the topic of pass/fail tests in constructors.

Later versions of PHP don't allow $this = null, so that's out.
Using unset($this) is allowed but is not reliable.

Consider the following:

   class a {
       function a($pass) {
           if (!$pass) unset($this);
       }
   }
  
   echo ($a = new a(true) ? "Passed" : "False") . "\n";
   echo ($a = new a(false) ? "Passed" : "False") . "\n";

The output:
False
False

However, if you add a member variable to the class and run the same script, the output becomes:
Pass
Pass

Basically the object evaluates to false if there are no member variables, otherwise true.  I'm guessing, but I believe calling unset($this) only unsets the reference to the object.  A copy of it is still passed back to the calling code.

To sum up, I would stick with the original recommended solution of having a property specifically to represent an object's status: initialized or failed.

class A {
  var $success;

  function A() {
     if (/* some fail test */)
       $this->success = false;
     // rest of your construct
  }
}
jfonseca at matarese dot com
19-May-2005 10:07
This will save you time if you're building a class hierarchy with 2 or more levels of inheritance.

$this always refers to the CURRENT INSTANCE. Therefore if you have:

class A{

   function A(){

   }

 // ....

}

class B extends A{

   function B(){

     // keep these 2 lines in mind
     $parentClass = get_parent_class($this);
     $this->$parentClass();

   }

 // ....

}

class C extends B{

   function C(){

     $parentClass = get_parent_class($this);
     $this->$parentClass();
     // here you will get into an infinite loop calling B();

   }

 // ....

}

Explanation: $this is an instance variable referring to the CURRENT INSTANCE, therefore the $this variable on class B will always be an instance of C, therefore get_parent_class($this) in class B will call the constructor of C's parent class, which is B again.

This is a hard to track error if you're a novice on PHP's  OO features mainly because PHP will not produce any warnings, errors or notices, nor will it log anything to Apache or the error_log file.

Keywords : infinite recursion, parent constructor, subclass
phpnotes at ionws dot com
05-Apr-2005 01:51
Just to possibly clarify something on this page: if you create an object of a derived class and the derived class has no constructor, then the base class's constructor will be automatically called.  For example:
<?php
class A {
   function
A() {
       echo
"A()\n";
   }
}

class
B extends A {
   function
foo() {
   }
}

$bar = new B;
// output: A()
?>

But if the derived class has a constructor, the base constructor is not automatically called.  For example:
<?php
class A {
   function
A() {
       echo
"A()\n";
   }
}

class
B extends A {
   function
B() {
       echo
"B()\n";
   }
   function
foo() {
   }
}

$bar = new B;
// output: B()
?>
herojoker at nexgo dot de
28-Feb-2005 11:28
Hi!

If you want to call the parent's constructor without knowing its name, just call

$this->{get_parent_class(__CLASS__)}($arg1, $arg2, ...);

Have fun with that.
Hero Wanders
john dot q dot webmaster at gmail dot com
25-Jan-2005 09:55
When testing the final example, I'm getting conflicting results with what the manual says.
-----
In PHP 3, the function B() in class A will suddenly become a constructor in class B, although it was never intended to be....

This is fixed in PHP 4 by modifying the rule to: 'A constructor is a function of the same name as the class it is being defined in.'. Thus in PHP 4, the class B would have no constructor function of its own and the constructor of the base class would have been called, printing 'I am the constructor of A.<br />'.
-----

I've just tested this on two systems, PHP (module) 4.3.7 and (CGI) 4.3.10.  BOTH of them print out the contents of B() when creating a new object of B.  This is contrary to the manual, which says this should only happen in PHP 3.

However, when testing the second to last example (where B() has no constructor), the behavior indicated for PHP 4 DOES happen; a constructor is called for 'new B', and it prints "I am the constructor of A.<br />".

What's happening here?
arjini at gmail dot com
24-Dec-2004 12:02
This wasn't apparent in the docs above (wording maybe?)

class A{
   function A(){
       echo 'A\'s constructor has been called.';
   }
}

class B {function C(){}}

$instance = new B();

//output: A's constructor has been called.
zax AT email DOT cz
03-Sep-2004 05:43
to: steffen-staehle at NO dot SPAM dot gmx dot de

I got an error by
$this=NULL

(Fatal error: Cannot re-assign $this ...),

you should use
unset($this)
instead, that works
23-Jun-2004 06:48
This is for Ivan...
If this is the case then what is the case of the constructors of the child class being defined in the parent class...
they also get called implicitly on anyinstance of the child class
31-Mar-2004 10:50
to propagate the call to constructors, here is a good method :

class B extends A
{
   var $var2;
  

   function B ($arg)
   {
       parent::A();  // Invoke the constructor of the parent.
   }

}
steffen-staehle at NO dot SPAM dot gmx dot de
02-Dec-2003 01:07
[in reply to ogarbe's comment (01-Apr-2003)]

Any object evaluation as boolean of the kind

<?
  
if ($a = new A())
   {
    
// success, use $a ...
  
}
?>

is dangerous. Whether an object evaluates as true or false seems to depend on its internal structure (I've tested on a rather oldish version of php (4.2.1), though, so this might have changed!). Even a successfully created object might evaluate as false. Compare the two classes:

<?
class TestBool1
{
   var
$somevar = 'hello world';

   function
TestBool1()
   {
     echo
"1 somevar is: $this->somevar<p>";

   }
// constructor

} // TestBool

if ($obj = new TestBool1())
   echo
'obj is valid<p>';
else
   echo
'obj is invalid<p>';

class
TestBool2
{
   function
TestBool2($somevar)
   {
     echo
"2 somevar is: $somevar<p>";

   }
// constructor

} // TestBool

if ($obj = new TestBool2('hello world'))
   echo
'obj is valid<p>';
else
   echo
'obj is invalid<p>';

?>

The output is:

1 somevar is: hello world
obj is valid

2 somevar is: hello world
obj is invalid

Case '2' is NOT what you would expect.

So at least you should use another comparison:

<?
class TestBool3
{
   function
TestBool3($somevar)
   {
     echo
"3 somevar is: $somevar<p>";
    
// assume error
    
$this = NULL;

   }
// constructor

} // TestBool

if (($obj = new TestBool3('hello world')) !== NULL)
   echo
'obj is valid<p>';
else
   echo
'obj is invalid<p>';
?>

This evaluates correctly and prints:

3 somevar is: hello world
obj is invalid

But Markus 16-Sep-2003 says assigning NULL to $this did not work any more with php 4.3.3. So what it boils down to: I still prefer the solution I have sketched below (steffen 17-Jan-2003).
20-Sep-2003 07:08
Adding to the last post...

If u DON'T WANT to override the parent creator just put

<?
// ...
  
function On_Create() {
      
parent::On_Create();
      
// Some code
  
}
//...
?>

It will calls the parent creator and u can extend how many classes do you even want to...
pigmeu at pigmeu dot net
20-Sep-2003 06:30
To workaround the problem that some people are having on multiple creator (or sub creators or whatever)...

Its just to use an event! Yes... U can emulate an event (like the inprize people do)

Here it goes:

<?

//This is the "generic" class... All other classes may extends from it...
class TObject {

   function
On_Create() { }

   function
TObject() {
      
$this->On_Create();
   }
}

class
TExtendedObject extends TObject {
   var
$name;

   function
On_Create() {
      
$this->name = "Test";
   }
}

$t_class = new TExtendedObject;
echo
$t_class->name;
/* output
Test
*/
?>

Nice... Isn't it?
markus at emedia-solutions-wolf dot de
16-Sep-2003 06:00
Setting $this to null isn't available in PHP 4.3.3R3 anymore. Maybe in version below also.
johan_php at popbandetleif dot cjb dot net
06-Apr-2003 08:31
/**
  * Example Class for getting around the problem with
  * overloaded functions constructors.
  *
  * This exapmple are asuming that you want to overload
  * the constructor Object() with different arguments. 
  */
class Object {

  /**
   * The real constuctor for this class.
   *
   * NOTE: Parlameter may not have the value null
   *      unless you changes the default value in
   *      the constructor.
   */
  function Object($param1 = null, $param2 = null) {
   $numargs = func_num_args();
   $arg_list = func_get_args();
   $args = "";
   for ($i = 0; $i < $numargs && $arg_list[$i] != null; $i++) {
     if ($i != 0) {
       $args .= ", ";
     }

     $args .= "\$param" . ($i + 1);
   }

   // Call constructor function
   eval("\$this->constructor" . $i . "(" . $args . ");");
  }

  /**
   * Functiorn that will be called if constructor is called
   * with no parlameter as agument.
   */
  function constructor0() {
   echo("Constructor 1: No parlameter." . "\n");
  }

  /**
   * Functiorn that will be called if constructor is called
   * with one parlameter as agument.
   */
  function constructor1($param) {
   echo("Constructor 2: \$param=" . $param . "\n");
  }

  /**
   * Functiorn that will be called if constructor is called
   * with two parlameter as agument.
   */
  function constructor2($param1, $param2) {
   echo("Constructor 3: \$param1=" . $param1 . "\n");
   echo("Constructor 3: \$param2=" . $param2 . "\n");
  }
}

new Object();
new Object("A String value");
new Object("Another String...", 1);

// Output:
Constructor 1: No parlameter.

Constructor 2: $param=A String value

Constructor 3: $param1=Another String...
Constructor 3: $param2=1
johan_php at popbandetleif dot cjb dot net
04-Apr-2003 04:39
As far as I understand php has a strange way of handeling over loaded contructors - only the last defined will be used.

e.g.

class Cl {
  function Cl($a, $b) {
   echo("B ");
  }

  function Cl($a) {
   echo("A ");
  }
}

new Cl(1);
new Cl(1, 2);

// Out puts:
// B B

// And at the contrary:
class Cl {
  function Cl($a, $b) {
   echo("B ");
  }

  function Cl($a) {
   echo("A ");
  }
}

new Cl(1);
new Cl(1, 2);

// Out puts:
// Warning: Missing argument 2 for cl() ...
ogarbe at tf1 dot fr
02-Apr-2003 03:01
to steffen staehle

If you want your constructor to possibly not create the object

class A
{
  function A()
  {
     // ...
     // some error occurred
     $this = null;
     return; 
  }
}

if ($a = new A())
{
  // success, use $a ...
}
steffen staehle
18-Jan-2003 12:11
A note on a constructor's return value:

When creating an instance of a class, 'new' obviously returns the object, not the constructor's return value (if any).

Still, it might be tempting to communicate the success or failure of constructing the object via a return value:

class A
{
   function A()
   {
       // ...
       // some error occurred
       return FALSE; 
   }
}

if ($a = new A())
{
   // success, use $a ...
}

THIS WILL NOT WORK the way intended.
'new' returns the object, the assignment returns the value of the assignment, i.e. the object, and whether an object evaluates as TRUE does not depend on the constructor's return value.

My preferred solution - set some object property during the construction phase that you can check against explicitely.
ianyates at yahoo dot com
15-Jan-2003 01:32
Although not very good practice, I had a use for it.

In PHP you can destroy an object using unset(object instance) from outside of the object, but I needed to destroy the object from within.
After much experimentation, I simply set $this to null within a function inside the object.
This had the desired affect of removing the object from memory.
Note that unsetting $this does not have the same affect.

It would be better practice to set a variable within the object when it needed to be destroyed and then pick this up externally to mark the object as destroyed.

Hope this helps someone.
dmarsh dot NO dot SPAM dot PLEASE at spscc dot ctc dot edu
19-Sep-2002 02:40
Manual Destructor Example Code:

class MyObject()

  var $x;

  function MyObject() {
   $x=array();
   register_shutdown_function(array(&$this, "UnMyObject"));
  }

  [...]

  function UnMyObject() {
   unset($this->$x); // not needed but used to demonstrate the register_shutdown_function
  }

}
eric+nospam at ypass dot net
05-May-2002 04:59
This works in PHP 4.1.2 and probably versions > 4.x.

Creating an object from a constructor of a different class type can be accomplished.

Note that you can NOT return an object from a constructor.  A constructor can never return a value.  However, you can set the value of $this to acheive this.

For example:
<?
class A
{
  function
A()
  {
  
$this = new B();
  }
}

class
B
{
  function
iamab()
  {
   echo
"i am an object of class B";
  }
}

$a = new A();
echo
'$a is a ' . get_class($a) . "\n";
$a->iamab()
?>

would print out:

$a is a b
i am an object of class B
13-Dec-2001 03:38
A couple of comments :
<<If a class has no constructor, the constructor of the base
class is being called, if it exists.>>

Actually the constructor of the base class is NOT called.
The child class inherits TWO copies of the father constructor,
one named after the father, one named after the child.
(other methods are also inherited by copy, as stated in the manual!)

The copied method named after the child is being called. For
most purposes this is the same, but beware of static variables.

class bar{
function bar($var = null){
static $methodname = "bar::bar";
if(isset($var)) $methodname = $var;
else echo "$methodname <b"."r>";
}
}

class foo extends bar{
function printMethods(){
bar::bar();
foo::bar();
foo::foo();
}
}

foo::printMethods(); // prints 3 bar::bar
foo::foo('foo::foo');
foo::bar('foo::bar');
foo::printMethods(); // prints bar::bar,foo::bar,foo::foo

$foo = new foo; // prints foo::foo
$bar = new bar; // prints bar::bar

Ivan