PHP Doku:: Konstruktoren und Destruktoren - language.oop5.decon.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchSprachreferenzKlassen und ObjekteKonstruktoren und Destruktoren

Ein Service von Reinhard Neidl - Webprogrammierung.

Klassen und Objekte

<<Autoloading

Sichtbarkeit>>

Konstruktoren und Destruktoren

Konstruktor

void __construct ([ mixed $args [, $... ]] )

PHP 5 erlaubt es Entwicklern, Konstruktormethoden für Klassen zu deklarieren. Klassen mit Konstruktormethoden rufen diese für jedes neu erzeugte Objekt auf, so dass Konstruktoren für alle Initialisierungen passend sind, die das Objekt brauchen könnte bevor es benutzt wird.

Hinweis: Konstruktoren von Vaterklassen werden nicht implizit aufgerufen, wenn die Kindklasse einen Konstruktor definiert. Um einen Vaterkonstruktor zu benutzen ist ein Aufruf von parent::__construct() innerhalb des Kindkonstruktors notwendig.

Beispiel #1 Die neuen, vereinheitlichten Konstruktoren verwenden

<?php
class BaseClass {
   function 
__construct() {
       print 
"Im BaseClass Konstruktor\n";
   }
}

class 
SubClass extends BaseClass {
   function 
__construct() {
       
parent::__construct();
       print 
"Im SubClass Konstruktor\n";
   }
}

$obj = new BaseClass();
$obj = new SubClass();
?>

Für die Abwärtskompatibilität sucht PHP 5 nach einer Konstruktorfunktion nach dem alten Stil mit dem Namen der Klasse, falls es keine __construct() Funktion für eine Klasse findet. Effektiv bedeutet das, dass der einzige Fall mit Kompatibilitätsproblemen derjenige einer Klasse mit dem Namen __construct() ist, welche für andere Zwecke benutzt wird.

Destruktor

void __destruct ( void )

PHP 5 führt ein Destruktorkonzept ähnlich dem anderer objektorientierter Programmiersprachen wie C++ ein. Die Destruktormethode wird aufgerufen, sobald alle Referenzen auf ein bestimmtes Objekt entfernt werden oder wenn das Objekt explizit zerstört wird, oder in beliebiger Reihenfolge am Ende des Skripts.

Beispiel #2 Destruktor Beispiel

<?php
class MyDestructableClass {
   function 
__construct() {
       print 
"Im Konstruktor\n";
       
$this->name "MyDestructableClass";
   }

   function 
__destruct() {
       print 
"Zerstoere " $this->name "\n";
   }
}

$obj = new MyDestructableClass();
?>

Wie Konstruktoren auch, werden Vaterdestruktoren nicht implizit durch die Engine aufgerufen. Um einen Vaterdestruktor zu benutzen muss man explizit die Funktion parent::__destruct() in der Destruktorimplementierung aufrufen

Hinweis:

Der Destruktor wird während der Skript Abschaltung aufgerufen, weshalb die Header immer bereits gesendet sind. Das aktuelle Verzeichnis während der Beendigungsphase des Skripts kann bei einigen SAPIs (z.B. Apache) ein anderes sein.

Hinweis:

Der Versucht eine Exception aus einem Destruktor (der in der Beendigungsphase des Skripts aufgerufen wurde) heraus zu werfen wird einen fatalen Fehler auslösen.


61 BenutzerBeiträge:
- Beiträge aktualisieren...
gratcypalma at gmail dot com
19.11.2010 20:46
here is my multiple constructor.

<?php
class foo {
    protected
$mam = 'mamam';
    function
__construct() {
        echo
'foo';
    }
}
class
bar extends foo {
    function
__construct() {
       
parent:: __construct(); // use parent method to call parent class
       
echo 'bar';
    }
}
class
foobar extends bar {
    function
__construct() {
       
parent:: __construct();
        echo
'foobar';
    }
}
$show = new foobar();

/* result is foobarfoobar */
?>
rayro at gmx dot de
14.09.2010 12:35
the easiest way to use and understand multiple constructors:

<?php
class A
{
    function
__construct()
    {
       
$a = func_get_args();
       
$i = func_num_args();
        if (
method_exists($this,$f='__construct'.$i)) {
           
call_user_func_array(array($this,$f),$a);
        }
    }
   
    function
__construct1($a1)
    {
        echo(
'__construct with 1 param called: '.$a1.PHP_EOL);
    }
   
    function
__construct2($a1,$a2)
    {
        echo(
'__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
    }
   
    function
__construct3($a1,$a2,$a3)
    {
        echo(
'__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
    }
}
$o = new A('sheep');
$o = new A('sheep','cat');
$o = new A('sheep','cat','dog');

// results:
// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog
?>
maramirezc WHERE star-dev DOTTED com
21.07.2010 23:14
Another way to emulate multiple constructors:

<?php
class MyClass {

  
// use a unique id for each derived constructor,
   // and use a null reference to an array,
   // for optional parameters
  
function __construct($id="", $args=null) {
      
// parent constructor called first ALWAYS
      
parent::__construct();

       echo
"main constructor\n";

     
// avoid null or other types
     
$id = (string) $id;

     
// allow default constructor
     
if ($id == "") { 
        
$id = "default";
      }

     
// just in case, use lowercase id
     
$id = "__cons_" strtolower($id);

     
$rc = new ReflectionClass("MyClass");

      if (!
$rc->hasMethod($id) {
         echo
"constructor $id not defined\n";
      }
      else {
       
// using "method references"
       
$this->$id($args);
      }

      
$rc = null;
   }
// function __construct

   // ALWAYS HAVE A default constructor,
   // that ignores arguments
  
function __cons_default($args=null) {
       echo
"Default constructor\n";
   }

  
// may have other constructors that expect different
   // argument types or argument count
  
function __cons_min($args=null) {
     if (!
is_array($args) || count($args) != 2) {
       echo
"Error: Not enough parameters (Constructor min(int $a, int $b)) !!!\n";
     }
     else {
        
$a = (int) $args[0];
        
$b = (int) $args[1];
        
$c = min($a,$b);
         echo
"Constructor min(): Result = $c\n";
     }
   }

  
// may use string index (associative array),
   // instead of integer index (standard array)
  
function __cons_fullname($args=null) {
     if (!
is_array($args) || count($args) < 2) {
       echo
"Error: Not enough parameters (Constructor fullname(string $firstname, string $lastname)) !!!\n";
     }
     else {
        
$a = (string) $args["firstname"];
        
$b = (string) $args["lastname"];
        
$c = $a . " " . $b;
         echo
"Constructor fullname(): Result = $c\n";
     }
   }

}
// class

// --> these two lines are the equivalent
$obj1 = new TestClass();
$obj2 = new TestClass("default");

// --> these two are specialized

// should be read as "$obj3 = new TestClass, min(99.7, 99.83);"
$obj3 = new TestClass("min", array(99.7, 99.83));

// should be read as "$obj4 = new TestClass, fullname("John", "Doe");"
$obj4 = new TestClass("fullname", array("firstname" => "John", "lastname" => "Doe"));

// --> these  two lack parameters
$obj5 = new TestClass("min", array());
$obj6 = new TestClass("fullname");

?>
alon dot peer at gmail dot com
20.06.2010 11:39
Another way to overcome PHP's lack of multi constructors support is to check for the constructor's parameters' type and variate the operation accordingly. This works well when the number of parameters stays the same in all your constructors' needs.

Example:

<?php

class Articles {

    private
$_articles_array;

    public function
__construct($input) {
        if (
is_array($input)) {
           
// Initialize articles array with input.
       
}
        else if (
$input instanceof SimpleXMLElement) {
           
// Initialize articles array by parsing the XML.
       
}
        else {
            throw new
Exception('Wrong input type');
        }
    }

}

?>
Anonymous
10.06.2010 13:50
Be careful when using a class as reference or copy in another one in regard of the __destruct() method:

<?php
class MyMainClass {
    private
$tables = array();
    public function
__construct() {       
        echo
"Create ",get_class($this), " Object!<br>";
    }
    public function
__destruct() {       
        echo
"Destroy ",get_class($this)," Object!<br>";
    }
    public function &
getSubClass($name) {
        if(!isset(
$this->tables[$name])) {
           
# This will result in NOT calling the __destruct() method when
            # unsetting an objct of MyMainClass
           
$this->tables[$name] = new MySubClass($this, $name);
           
# If you clone the class (for testing) it will work as expected
            // $this->tables[$name] = new MySubClass(clone $this, $name);
       
}
        return
$this->tables[$name];
    }
}

class
MySubClass {
    private
$name = null;
    private
$main_class = null;
    public function
__construct(MyMainClass &$main_class, $name) {       
        echo
"Create ",get_class($this), " '$name' Object!<br>";
       
$this->name = $name;
       
$this->main_class = $main_class;
    }
    public function
__destruct() {
        echo
"Destroy ",get_class($this)," '$this->name' Object!<br>";
    }
}

$my = new MyMainClass($logger);
$my->getSubClass('bar');
$my->getSubClass('foo');
unset(
$my);
echo
"_____End of skript reached!_____<br>";
?>

This will result in:

Create MyMainClass Object!
Create MySubClass 'bar' Object!
Create MySubClass 'foo' Object!
_____End of Skript reached!_____
Destroy MyMainClass Object!
Destroy MySubClass 'bar' Object!
Destroy MySubClass 'foo' Object!
Anonymous
15.04.2010 8:07
If you are not aware of the parameter list, you could use the following in __construct to call up the chain:

<?php
$args
= func_get_args();
call_user_func_array(array($this, 'parent::__construct'), $args);
?>
thomasrutter
27.02.2010 12:20
The manual page says that throwing an exception from a destructor causes a fatal error;  I've found that this only happens when the exception is _uncaught_ within the context of that destructor.  If you catch it within that same destructor it seems to be fine.

This is equally true of other contexts, such as:
- shutdown functions set with register_shutdown_function
- destructors
- custom session close functions
- custom error handlers
- perhaps other similar contexts

An exception normally 'bubbles up' to higher and higher contexts until it is caught, but because a destructor or shutdown function is called not within execution flow but in response to a special PHP event, the exception is unable to be traced back any further than the destructor or shutdown function in which it is called.
Jonathon Hibbard
10.01.2010 1:32
Please be aware of when using __destruct() in which you are unsetting variables...

Consider the following code:
<?php
class my_class {
  public
$error_reporting = false;

  function
__construct($error_reporting = false) {
   
$this->error_reporting = $error_reporting;
  }

  function
__destruct() {
    if(
$this->error_reporting === true) $this->show_report();
    unset(
$this->error_reporting);
  }
?>

The above will result in an error:
Notice: Undefined property: my_class::$error_reporting in my_class.php on line 10

It appears as though the variable will be unset BEFORE it actually can execute the if statement.  Removing the unset will fix this.  It's not needed anyways as PHP will release everything anyways, but just in case you run across this, you know why ;)
jon at fatcatsoftware dot net
3.12.2009 22:33
I'm not sure why this was happening, but I had an instance were the __destruct was being called BEFORE my __construct in a certain class.

I'm using a Factory Class where I would call this statement to grab the class:
<?php
public static function &getBookingSession()
    {
        static
$instance =null;
       
        if (
is_null($instance))
        {
           
//requiring the class file
           
require_once 'bookingSession.php';
           
           
//request the instance
           
$instance = new bookingSession();
        }

        return
$instance;
    }
?>

The __destruct was actually being called each time I grabbed this class with

<?php $session =& Factory::getBookingSession(); ?>

Only after the destruct ran once or twice the construct would run. Obviously causing some major problems.

MY SOLUTION: was to call the register shutdown function in my fake session construct, like so:

<?php
class bookingSession {

function
__construct(){
       
$session =& Factory::getSession();
       
$this->setProperties( unserialize(base64_decode( $session->get('bookingSession') )) );
       
$this->setProperties(JRequest::get('post'));
       
       
register_shutdown_function(array($this,"destruct"));
    }

 */
    function
destruct() {
       
$session =& JFactory::getSession();
       
$session->set( 'bookingSession', base64_encode (serialize ($this)) );
    }
}
?>
ruggie0 at yahoo dot com
11.10.2009 13:13
For those who still ***have*** to deal with php4 (like myself, which sucks), contact at tcknetwork dot com noted below that you can have both __constructor and function [classname] in the script, as __constructor has priority.

However, to further improve compatability, do a version check in function [classname], as I do in my classes as follows:
<?php
  
class Foo{
      function
__construct($arg){
         echo
$arg;
      }

      function
Foo($arg){
         if(
version_compare(PHP_VERSION,"5.0.0","<")){
           
$this->__construct($arg);
           
register_shutdown_function(array($this,"__destruct"));         
         }
      }

      function
__destruct(){
         echo
"Ack! I'm being destroyed!";
      }
   }
?>

This makes it much easier to use your script with fewer compatibility issues.
enrico dot modanese at alpj dot com
23.08.2009 16:05
It's usefull to note that parent::__construct() is executed like a standalone function called into the new one, and not like a first part of the code. So "return" or "die()" don't have effect on following code. If you want to avoid the execution of the child constructor you have to pass some condition from the parent. Example:

<?php
class X {
  function
X(){
    if(
$_POST['break']=='yes'){return;}
    }
  }

class
Y extends X{
  function
Y(){
   
parent::__construct();
    print(
"Y_constructor_finished");
    }
  }

$_POST['break']=='yes';
$new_Y=new Y();  // will print "Y_constructor_finished"

Solution:

class
X {
  function
X(){
    if(
$_POST['break']=='yes'){$this->break='yes';return;}
    }
  }

class
Y extends X{
  function
Y(){
   
parent::__construct();
    if(
$this->break=='yes'){return;}
    print(
"Y_constructor_finished");
    }
  }

$_POST['break']='yes';
$new_Y=new Y();  // will print nothing
?>
ramesh dot rips at gmail dot com
26.06.2009 15:49
Without __constructor constructor will call like this.
Why because, Here Class name and function name are equal.
<?php
class baseclass
{
  function
baseclass()
  {
    echo
"constructor is called"."<br>" ;
   }
 }
 class
deriviedclass extends baseclass
 
{
   function
deriviedclass()
   {
      
parent::baseclass();
     }
  }
 
 
$object_base=new baseclass();
 
$object_derive=new deriviedclass();
?>
Out put is
constructor is called
constructor is called
hyponiq at gmail dot com
21.05.2009 3:43
I just thought I'd share some valuable information that might help novice programmers/scripters in __constructor() functions.

I've been using PHP for quite a long time, as well as programming and scripting in general.  Even with my quite seasoned skillset, I still make obvious, painstaking mistakes.  That said, I'd like to point out one major (albeit obvious) common mistake that programmers and scripters (such as myself) make.

When defining the constructor for an object and using it to populate variables for use throughout the lifetime of the application, do note that if you set a static variable AFTER a dynamic one, the static variable's (intended) contents are not readible inside the assigning functions of a dynamic variable.  (That sounded rather cryptic, so an example is in order...)

<?php
class ExampleClass
{
   
// assigned a static value using an expression in the constructor
   
public $myStaticVar;
   
   
// assigned a value through a function of the class
   
public $myDynamicVar;
   
    public function
__construct($myStaticVarValue)
    {
       
// sets to nothing; $this->myStaticVar hasn't been assigned to yet
       
$this->myDynamicVar = $this->setSomeValue();
       
       
// sets to 'Static Variable Value in this example
       
$this->myStaticVar = $myStaticVarValue;
    }
   
    public function
setSomeValue()
    {
       
// returns null; $this->myStaticVar hasn't been assigned to, yet
       
return $this->myStaticVar;
    }
}

// automatically sets $object->myStaticVar to 'Static Variable Value'
//(but only after setting $object->myDynamicVar to the unassigned $object->myStaticVar)
$object = new ExampleClass('Static Variable Value');

// outputs nothing
print $object->myDynamicVar;
?>

The above example won't print anything because you're setting the $myDynamicVar to equal the $myStaticVar, but the $myStaticVar hasn't been (technically) assigned to, yet.

So, if you wish to reference that variable inside the assignment function of a dynamic variable, you have to declare it first and foremost.  Otherwise, its value will not be accessible yet.

The correct way...
<?php
class ExampleClass
{
   
// assigned a static value using an expression in the constructor
   
public $myStaticVar;
   
   
// assigned a value through a function of the class
   
public $myDynamicVar;
   
    public function
__construct($myStaticVarValue)
    {
       
// sets to $myStaticVariable (or 'Some Static Variable Value' in this example)
       
$this->myStaticVar = $myStaticVarValue;
       
       
// sets to newly assigned-to $this->myStaticVariable
       
$this->myDynamicVar = $this->setSomeValue();
    }
   
    public function
setSomeValue()
    {
       
// returns 'Static Variable Value'
       
return $this->myStaticVar;
    }
}

// sets $object->myStaticVar to 'Static Variable Value' automatically before $object->myDynamicVar
$object = new ExampleClass('Static Variable Value');

// outputs 'Static Variable Value'
print $object->myDynamicVar;
?>
ceo at l-i-e dot com
7.05.2009 19:38
As far as I can tell, Connection: close isn't sent until after __destruct is called in shutdown sequence.
I was hoping to get the HTTP connection closed and done, and do some slow non-output processing after that, but no luck.
bac2day1 at gmail dot com
29.01.2009 19:26
You can also capitalize on singleton for the connection as well.
Just add the following to your class:

<?php
class db {
 
//...
 
private static $instance;
 
//...
 
public static function singleton() {
    if(!isset(
self::$instance)) {
     
$c = __CLASS__;
     
self::$instance = new $c();
    }
    return
self::$instance;
  }
 
//...
}
?>
spleen
18.10.2008 1:35
It's always the easy things that get you -

Being new to OOP, it took me quite a while to figure out that there are TWO underscores in front of the word __construct.

It is __construct
Not _construct

Extremely obvious once you figure it out, but it can be sooo frustrating until you do.

I spent quite a bit of needless time debugging working code.

I even thought about it a few times, thinking it looked a little long in the examples, but at the time that just seemed silly(always thinking "oh somebody would have made that clear if it weren't just a regular underscore...")

All the manuals I looked at, all the tuturials I read, all the examples I browsed through  - not once did anybody mention this! 

(please don't tell me it's explained somewhere on this page and I just missed it,  you'll only add to my pain.)

I hope this helps somebody else!
office at kitsoftware dot ro
14.10.2008 16:01
Should be noted that according to the NEWS (in PHP 5.3) file, in PHP 5.3, handling an exception in the __destructor should not output a FATAL error ...
Jeffrey
9.10.2008 23:04
Constructor Simplicity

If your class DOES CONTAIN instance members (variables) that need to be set, then your class needs to be initialized... and you should use __construct() to do that.

<?php
class MyClassA {
  public
$data1, $data2;

  public function
__construct($mcd1, $mcd2) {
   
$this->data1 = $mcd1// INITIALIZE $data1
   
$this->data2 = $mcd2// INITIALIZE $data2
 
}
}

$obj1 = new MyClassA("Hello", "World!");  // INSTANTIATE MyClassA
$d1 = $obj1->data1;
$d2 = $obj1->data2;
?>

If your class DOES NOT CONTAIN instance members or you DO NOT want to instantiate it, then there is no reason to initialize it or use __construct().

<?php
class MyClassB {
  const
DATA1 = "Hello";
  public static
$data2 = "World!";
}

$obj1 = new MyClassB();  // INSTANTIATE MyClassB - NO error.
$d1 = $obj1::DATA1;      // ERROR
$d2 = $obj1::data2;      // ERROR
$d1 = MyClassB::DATA1;   // ok
$d2 = MyClassB::$data2// ok
?>

The fact that $obj1 is useless and cannot be used as a reference, is further evidence that MyClassB objects should not be instantiated. NOTICE that MyClassB does not use private members or functions to make it behave that way. Rather, it is the collective nature of all the class members + what ISN'T there.
Anonymous
10.09.2008 2:42
USE PARENT::CONSTRUCT() to exploit POLYMORPHISM POWERS

Since we are still in the __construct and __destruct section, alot of emphasis has been on __destruct - which I know nothing about. But I would like to show the power of parent::__construct for use with PHP's OOP polymorphic behavior (you'll see what this is very quickly).

In my example, I have created a fairly robust base class that does everything that all subclasses need to do. Here's the base class def.

<?php

/*
 * Animal.php
 *
 * This class holds all data, and defines all functions that all
 * subclass extensions need to use.
 *
 */
abstract class Animal
{
  public
$type;
  public
$name;
  public
$sound;

 
/*
   * called by Dog, Cat, Bird, etc.
   */
 
public function __construct($aType, $aName, $aSound)
  {
   
$this->type = $aType;
   
$this->name = $aName;
   
$this->sound = $aSound;
  }

 
/*
   * define the sorting rules - we will sort all Animals by name.
   */
 
public static function compare($a, $b)
  {
    if(
$a->name < $b->name) return -1;
    else if(
$a->name == $b->name) return 0;
    else return
1;
  }

 
/*
   * a String representation for all Animals.
   */
 
public function __toString()
  {
    return
"$this->name the $this->type goes $this->sound";
  }
}

?>

Trying to instantiate an object of type Animal will not work...

$myPet = new Animal("Parrot", "Captain Jack", "Kaaawww!"); // throws Fatal Error: cannot instantiate abstract class Animal.

Declaring Animal as abstract is like killing two birds with one stone. 1. We stop it from being instantiated - which means we do not need a private __construct() or a static getInstance() method, and 2. We can use it for polymorphic behavior. In our case here, that means "__construct", "__toString" and "compare" will be called for all subclasses of Animal that have not defined their own implementations.

The following subclasses use parent::__construct(), which sends all new data to Animal. Our Animal class stores this data and defines functions for polymorphism to work... and the best part is, it keeps our subclass defs super short and even sweeter.

<?php

class Dog extends Animal{
  public function
__construct($name){
   
parent::__construct("Dog", $name, "woof!");
  }
}

class
Cat extends Animal{
  public function
__construct($name){
   
parent::__construct("Cat", $name, "meeoow!");
  }
}

class
Bird extends Animal{
  public function
__construct($name){
   
parent::__construct("Bird", $name, "chirp chirp!!");
  }
}

# create a PHP Array and initialize it with Animal objects
$animals = array(
  new
Dog("Fido"),
  new
Bird("Celeste"),
  new
Cat("Pussy"),
  new
Dog("Brad"),
  new
Bird("Kiki"),
  new
Cat("Abraham"),
  new
Dog("Jawbone")
);

# sort $animals with PHP's usort - calls Animal::compare() many many times.
usort($animals, array("Animal", "compare"));

# print out the sorted results - calls Animal->__toString().
foreach($animals as $animal) echo "$animal<br>\n";

?>

The results are "sorted by name" and "printed" by the Animal class:

Abraham the Cat goes meeoow!
Brad the Dog goes woof!
Celeste the Bird goes chirp chirp!!
Fido the Dog goes woof!
Jawbone the Dog goes woof!
Kiki the Bird goes chirp chirp!!
Pussy the Cat goes meeoow!

Using parent::__construct() in a subclass and a super smart base class, gives your child objects a headstart in life, by alleviating them from having to define or handle several error and exception routines that they have no control over.

Notice how subclass definitions are really short - no variables or functions at all, and there is no private __construct() method anywhere? Notice how objects of type Dog, Cat, and Bird are all sorted by our base class Animal? All the class definitions above address several issues (keeping objects from being instantiated) and enforces the desired, consistent, and reliable behavior everytime... with the least amount of code. In addition, new extenstions can easily be created. Each subclass is now super easy to redefine or even extend... now that you can see a way to do it.
KK
16.05.2008 22:57
I ran into an interesting (and subtle) code error while porting some code to PHP 5.2.5 from PHP 4.4.8 that I think illustrates a noteworthy semantic.

I have a hierarchy of classes with both styles of constructors but where one in the middle was missing the __construct() function (it just had the old-style one that called the (nonexistent) __construct()).  It worked fine in PHP4 but caused an endless loop (and stack overflow) in PHP5.  I believe what happened is that in PHP4 the old-style constructor was not called, but in PHP5 it was (due to the "emulation" of PHP4), and since _construct() wasn't defined for that class, the call to $this->__construct() caused a looping call to the original (lowest child) constructor.
bolshun at mail dot ru
17.04.2008 3:13
Ensuring that instance of some class will be available in destructor of some other class is easy: just keep a reference to that instance in this other class.
ashnazg at php dot net
12.04.2008 19:26
Since my last note, I've been instructed to _NEVER_ call "unset($this)", never ever ever.  Since my previous testing of behavior did not explicitly show me that it was indeed necessary, I'm inclined to trust those telling me not to do it.
ashnazg at php dot net
28.02.2008 23:39
While experimenting with destructs and unsets in relation to memory usage, I found what seems to be one useful way to predict when __destruct() gets called... call it manually yourself.

I had previously assumed that explicitly calling unset($foo) would cause $foo->__destruct() to run implicitly, but that was not the behavior I saw (php 5.2.5).  The destructors weren't running until the script ended, even though I was calling unset($foo) in the middle of my script.  So, having $foo->__destruct() unset all of $foo's component objects was not helping my memory usage since my explicit unset($foo) was _not_ triggering $foo->__destruct()'s cleanup steps.

Interestingly, what _did_ appear to happen is that calling unset($bar) from inside a destructor like $foo->__destruct() _DID_ cause $bar->__destruct() to be implicitly executed.  Perhaps this is because $bar has a "parent" reference of $foo whereas $foo does not, and the object destruction behaves differently... I don't know.

Lastly, even after explicitly calling $foo->__destruct() (even when it had "unset($this);" inside it), the reference to the $foo object remained visible.  I had to still explicitly call unset($foo) to get rid of it.

So, my advice based on the behavior I saw in my experiments:
- always unset($bar) your class's component objects from inside that class's __destruct() method;  no explicit component destructor calls seem to be required other than those unsets, though.
- always explicitly call $foo->__destruct() in your code that _uses_ your class
- always explicitly follow $foo->__destruct() with unset($foo).

This seems to be the best cleanup approach to take.  Just for my own sanity, I also will always keep an unset($this) at the end of each __destruct() method.
nerdystudmuffin at gmail dot com
9.01.2008 20:11
Correction to the previous poster about non public constructors. If I wanted to implement Singleton design pattern where I would only want one instance of the class I would want to prevent instantiation of the class from outside of the class by making the constructor private. An example follows:

class Foo {

  private static $instance;

  private __construct() {
    // Do stuff
  }

  public static getInstance() {

    if (!isset(self::$instance)) {
      $c = __CLASS__;
      $instance = new $c;
    }

    return self::$instance;
  }

  public function sayHello() {
    echo "Hello World!!";
  }

}

$bar = Foo::getInstance();

// Prints 'Hello World' on the screen.
$bar -> sayHello();
david at synatree dot com
29.12.2007 22:26
When a script is in the process of die()ing, you can't count on the order in which __destruct() will be called.

For a script I have been working on, I wanted to do transparent low-level encryption of any outgoing data.  To accomplish this, I used a global singleton class configured like this:

class EncryptedComms
{
    private $C;
    private $objs = array();
    private static $_me;
   
    public static function destroyAfter(&$obj)
    {
        self::getInstance()->objs[] =& $obj;
        /*
            Hopefully by forcing a reference to another object to exist
            inside this class, the referenced object will need to be destroyed
            before garbage collection can occur on this object.  This will force
            this object's destruct method to be fired AFTER the destructors of
            all the objects referenced here.
        */
    }
    public function __construct($key)
    {
            $this->C = new SimpleCrypt($key);
            ob_start(array($this,'getBuffer'));
    }
    public static function &getInstance($key=NULL)
    {
        if(!self::$_me && $key)
            self::$_me = new EncryptedComms($key);
        else
            return self::$_me;
    }
   
    public function __destruct()
    {
        ob_end_flush();
    }
   
    public function getBuffer($str)
    {
        return $this->C->encrypt($str);
    }

}

In this example, I tried to register other objects to always be destroyed just before this object.  Like this:

class A
{

public function __construct()
{
     EncryptedComms::destroyAfter($this);
}
}

One would think that the references to the objects contained in the singleton would be destroyed first, but this is not the case.  In fact, this won't work even if you reverse the paradigm and store a reference to EncryptedComms in every object you'd like to be destroyed before it.

In short, when a script die()s, there doesn't seem to be any way to predict the order in which the destructors will fire.
Typer85 at gmail dot com
22.12.2007 6:33
I mentioned in my post below this one that the solution is not perfect and has some flaws.

Because my note was too big and was not allowed to be submitted, I had to write a new note here containing the flaws. If an editor sees this, please combine both notes to allow for easier reading.

- This solution assumes that Class B and Class C extend or build upon Class AAbstract. If Class B or Class C extend from each other or from Class A, the original problem will be encountered again.

- There will be extra overhead in including an extra file ... the dummy Class AAbstract.
Typer85 at gmail dot com
22.12.2007 6:31
In regards to a Class Constructor visibility ...

I too was having the same problem with Class Constructor visibility, in which I had one Class that was extended by several other Classes. The problem that I encountered was in one of the Child Classes, I wanted a weaker visibility. Consider the following example:

<?php

class A {
   
   
// Public Constructor ...
    // No Problems Here.
   
   
public function __construct( ) {
       
    }
   
   
// Class Function.
   
   
public function functionA( ) {
       
    }
}

class
B extends A {
   
   
// Public Constructor ...
    // Same As Parent Class ...
    // Again No Problems Here.
   
   
public function __construct( ) {
       
    }
   
   
// Class Function.
   
   
public function functionB( ) {
       
    }
}

class
C extends A {
   
   
// Private Constructor ...
    // Weaker Then Parent Class ...
    // PHP Will Throw A Fatal Error.
   
   
private function __construct( ) {
       
    }
   
   
// Class Function.
   
   
public function functionC( ) {
       
    }
}

?>

Nothing new in the above example that we have not seen before. My solution to solve this problem?

Create an Abstract Class with all the functionality of Class A.  Make its Class Constructor have a visibility of Protected, then extend each of the three Classes above from that Abstract Class. In a way, the Abstract Class acts as a dummy Class to get rid of the visibility problem:

<?php

abstract class AAbstract {
   
   
// Protected Constructor ...
    // Abstract Class Can Not Be Created Anyway ...
    // No Problems Here.
   
   
protected function __construct( ) {
       
    }
   
   
// Class Function ...
    // Originally In Class A ...
    // Which Was Used As A Super Class.
   
   
public function functionA( ) {
       
    }
}

class
A extends AAbstract {
   
   
// Public Constructor ...
    // Stronger Than Parent Class ...
    // Again No Problems Here.
   
   
public function __construct( ) {
       
       
// By Moving All The Functionality Of
        // Class A To Class AAbstract Class A
        // Will Automatically Inherit All Of
        // Its Functionality. The Only Thing
        // Left To Do Is To Create A Constructor
        // Which Calls Class AABstract's Constructor
        // To Mimic Similar Behavior.
       
       
parent::__construct( );
    }
   
   
// No Need To Redeclare functionA( )
    // Since It Was Moved To Class
    // AAbstract.
}

class
B extends AAbstract  {
   
   
// Public Constructor ...
    // Stronger Than Parent Class ...
    // Again No Problems Here.
   
   
public function __construct( ) {
       
       
parent::__construct( );
    }
   
   
// Class Function ...
    // Specific To This Class.
   
   
public function functionB( ) {
       
    }
}

class
C extends AAbstract {
   
   
// Protected Constructor ...
    // Same As Parent Class ...
    // Again No Problems Here.
   
   
protected function __construct( ) {
       
    }
   
   
// Class Function ...
    // Specific To This Class.
   
   
public function functionC( ) {
       
    }
}

?>

As you can see the problem is more or less fixed. Class AAbstract acts a dummy class, containing all the original functionality of Class A. But because it has a protected Constructor, in order to make its functionality available, Class A is redeclared as Child Class with the only difference of it having a public Constructor that automatically calls the Parent Constructor.

Notice that Class B does not extend from Class A but also from Class AAbstract! If I wanted to change Class B's Constructor to protected, I can easily do it! Notice that an extra Method was added to Class B ... this is because Class B has extra functionality specific to itself. Same applies to Class C.

Why don't Class B and Class C extend from Class A? Because Class A has a public Constructor, which pretty much defies the point of this solution.

This solution is not perfect however and has some flaws.

Good Luck,
randallgirard at hotmail dot com
26.10.2007 19:17
I've been working on a project for a while now, and for example in my DB handler I wanted to load var's to the objects late; However, without doing it manually on the object itself but through a single static call. For other reasons, in my Sessions I then wanted to end them early without registering a shutdown routine for every possible session. Hence, I needed a way to track EVERY instance or object of the class.

(Of course in a normal website design, this would be overly coded. It's more of a framework for a CMS, Daemon service, anything I wanna create etc...)

<?php

class example {

    public static
$OBJS = array();
    public
$id;
   
    public function
__construct() {
       
example::$OBJS[] = $this;
   
# I actually use a 'lastKey' routine here, but in this example the following should work:
       
$this->id = key( array_slice(example::$OBJS, count(example::$OBJS) -1, 1, true) );
    }
   
    public function
__destruct() {
       
$this->close();
    }
   
# unset the tracked object
   
private function destruct() {
        if ( isset(
example::$OBJS[$this->id]) )
            unset(
example::$OBJS[$this->id]);
    }
   
# public shutdown routine
   
public function close() {
        if ( isset(
$this->destructed) )
            return;
   
# ...
       
$this->destruct();
       
$this->destructed = true;
    }
   
}

?>

You could then also use register_shutdown_function(...) to call a static class method, which loops through ALL the objects and calls the $obj->close routine.

<?php

# register a shutdown function which triggers before destructors (hence when such results are desired for a Session class, etc)
   
register_shutdown_function("example::destructors");
   
class
example {
   
   
# ... see above code example
   
# static class method to destruct all objects
   
public static function destructors() {
        foreach (
example::$OBJS as $obj )
           
$obj->destruct();
    }
   
}

This will probably give some people new ideas, and other will probably be confused. Happy coding...

NOTE: I didn't test the code(s) above. They were a rewritten example from my frameworks.

?>
James Laver
25.10.2007 11:45
I recently found, while implementing a database backed session class, that PHP has an apparently less than desirably structured destruction order. Basically, my session class which would have saved when destructed, was being destructed after one of the classes it depends on. Apparently we cannot, therefore depend on PHP to use reverse initialisation order.

My solution was to use register_shutdown_function, which is called before any objects are killed on script end.

Quick example (if you're going to use it, I recommend tidying up the code somewhat) :
<?php
class Session
 
function __construct()
  {
   
//Initialise the session here...
   
    //Register the shutdown function
   
register_shutdown_function(array($this,"save"));
  }

  function
save()
  {
   
//Save it here
 
}

  function
__destruct()
  {
   
//Persisting the session here will not work.
 
}
?>
magus do t xion a t g mail d ot c o m
11.10.2007 21:20
Looking through the notes I noticed a few people expressing concern that PHP5 does not support multiple constructors...

Here is an example of a method that I use which seems to work fine:

class Example
{
     function __construct()
     {
           echo "do some basic stuff here";
     }

     function Example($arg)
     {
           echo $arg;
     }
}

You then can call with or without arguments without having notices and/or warnings thrown at you... Of course this is limited but if you don't need something complex this can help to get the job done in some situations.  I believe you could also add arguments to the __construct() function and as long as it is different than Example() 's args you would be fine. Although I have yet to test this.
prieler at abm dot at
27.07.2007 9:42
i have written a quick example about the order of destructors and shutdown functions in php 5.2.1:

<?php
class destruction {
    var
$name;

    function
destruction($name) {
       
$this->name = $name;
       
register_shutdown_function(array(&$this, "shutdown"));
    }

    function
shutdown() {
        echo
'shutdown: '.$this->name."\n";
    }

    function
__destruct() {
        echo
'destruct: '.$this->name."\n";
    }
}

$a = new destruction('a: global 1');

function
test() {
   
$b = new destruction('b: func 1');
   
$c = new destruction('c: func 2');
}
test();

$d = new destruction('d: global 2');

?>

this will output:
shutdown: a: global 1
shutdown: b: func 1
shutdown: c: func 2
shutdown: d: global 2
destruct: b: func 1
destruct: c: func 2
destruct: d: global 2
destruct: a: global 1

conclusions:
destructors are always called on script end.
destructors are called in order of their "context": first functions, then global objects
objects in function context are deleted in order as they are set (older objects first).
objects in global context are deleted in reverse order (older objects last)

shutdown functions are called before the destructors.
shutdown functions are called in there "register" order. ;)

regards, J
fredrik at rambris dot com
16.07.2007 15:59
The fact that class names are case-insensitive in PHP5 also applies to constructors. Make sure you don't have any functions named like the class *at all*.

This has bitten me a few times.

<?php
class Example extends Base
{
  function
example()
  {
    echo
"This gets called";
  }
}

class
Base
{
  function
__construct()
  {
    echo
"Not this";
  }
}

?>
theubaz at gmail dot com
12.07.2007 1:35
What you could do is write the constructor without any declared arguments, then iterate through the arguments given and check their types/values to determine what other function to use as the constructor.
soapthgr8 at gmail dot com
6.07.2007 16:46
This is just to clarify that the Singleton pattern is a bit more complex than just making the constructor private. It also involves caching an instance of the object and always returning the cached value. So, in the previous example, the getNewInstance() function would undermine the intent of the Singleton pattern. Instead you would just need a getInstance() function, like so.

<?php
class A {
 
// cached instance
 
private static oInst = null;

 
/**
    * Prevent an object from being constructed.
    */
 
private function __construct( ) {}
 
/**
   * Function to return the instance of this class.
   */
 
public static function getInstance( ) {
    if (
is_null(self::$oInst)) {
     
self::$oInst = new A( );
    }
    return
self::$oInst;
  }
}
?>
Typer85 at gmail dot com
3.06.2007 16:16
I am not sure if the following is known or not, but here goes.

I am sure most are aware of the concept of making a Class Constructor private to prevent an Object of that Class from being created as follows:

<?php

class A
{
   
/**
     * Prevent An Object From Being Constructed.
     */
   
private function __construct( ) {
       
    }
}

?>

In some code, if I try to do the following:

<?php

$Obj
= new A( );

?>

PHP will fail with a fatal error. This is useful when creating Classes that are composed of only static functions or in a more advanced example, when applying the Singleton Pattern to a Class design.

However what is not properly documented in this manual but is pretty simple to note, especially if you read the notes regarding the Singleton Pattern, is that you can create an Object of a Class that has a private Constructor from within the Class itself.

Confused ... so am I, so allow me to provide a visual example as follows:

<?php

class A
{
   
/**
     * Prevent An Object From Being Constructed.
     */
   
private function __construct( ) {
       
    }
   
/**
     * Function To Return An Instance Of This Class.
     */
   
public static function getNewInstance( ) {
       
        return new
A( );
    }
}

?>

In some code, if I try to do the following:

<?php

$Obj
= A::getNewInstance( );

?>

PHP in this case will not fail with a fatal error and instead the variable '$Obj' becomes an Object with an instance of Class 'A'.

This is a simple example and pretty advanced things can be done using this method. I am sure advanced developers are aware of this so this is just a little note going out to new PHP developers.
Peter Molnar
17.05.2007 17:32
The manual says: "Destructor is called during the script shutdown so headers are always already sent."

This is obviously not true. If you instantiate a class in a function or class method, but it is not returned by the method, nor is it saved in a global or object member variable, the object is cleaned up, and it's destructor is called. This can of course occur before anything is printed or sent to the client.
frederic dot barboteu at laposte dot net
15.04.2007 4:11
The manual says:
"Like constructors, parent destructors will not be called implicitly by the engine."

This is true ONLY when a __destruct() function has been defined by the child class.
If no __destruct() function exists in the child class, the parent's one will be implicitly executed.

So be carefull if you have some ancestor executing a particular task in its __destruct() function, an you plan its childs to execute it or not, wether you include "parent::__destruct()" or not.
If you want the child not to execute its parent __destruct() function, you must ensure that it has its own __destruct() function, even if empty. Then the parent's one will not be executed.

This can be verified with the following code:
<?php
#
class AncestorClass {
    function
__destruct() {
        echo
'<br />AncestorClass: destructing '.get_class($this);
    }
}
#
class ParentDestructClass extends AncestorClass {
    function
__destruct() {
        echo
'ParentDestructClass: destructing itself';
       
parent::__destruct();
    }
}
#
class EmptyDestructClass extends AncestorClass {
    function
__destruct() {
        echo
'EmptyDestructClass: destructing itself';
    }
}
#
class NoDestructClass extends AncestorClass {
}
#---
echo '<hr>';
$p=new ParentDestructClass();
unset(
$p);
echo
'<hr>';
$e=new EmptyDestructClass();
unset(
$e);
echo
'<hr>';
$n=new NoDestructClass();
unset(
$n);
echo
'<hr>';
?>
which displays:
---
ParentDestructClass: destructing itself
AncestorClass: destructing ParentDestructClass
---
EmptyDestructClass: destructing itself
---

AncestorClass: destructing NoDestructClass
---
robert at lax-berlin dot de
12.11.2006 21:48
In response to prauscher at gmx dot net:

As tcknetwork wrote earlier, if you try to access a file from a destructor, you have to be aware that you are probably in the webservers root directory, because the destructor already "forgot" what you working directory was. If you try to write a file there, you will probably have no permission to do so.
Read tcknetwork's post for a solution.
maniac_warlord at web dot de
4.11.2006 13:50
as reported in bug 34206 the working dir is changed to the server root
the best workaround is
<?php
class Foo
{
    public function
bar()
    {
           
$this->_cwd = getcwd();
    }

    public function
__destruct()
    {
       
chdir($this->_cwd);
    }
}
?>
Be aware the booty trap!
http://bugs.php.net/bug.php?id=34206
phaxius
2.11.2006 6:23
Hello, I've been messing with php for about a week but am learning a lot.  It occurred to me that it might be necessary in some cases to write a class that takes a variable number of arguments.  After some experimentation, this example was formed:

class variableArgs{
public $a = array();
protected $numOfArgs;
public function __construct()
{
  $numOfArgs=func_num_args();
  if(func_num_args()==0)
  {
    $numOfArgs=1;
    $a[0]='No arguments passed';
    $this->Arg[0]=$a[0];
  }
  else
  for($i=0; $i<func_num_args(); $i++)
  {
    $a[$i]=func_get_arg($i);
    $this->Arg[$i]=$a[$i];
  }
}
public function showArgs()
{
  echo 'showArgs() called <br />';
  for ($i=0; $i<$numOfArgs; $i++)
  {
    echo '$i: ' . $i . '<br />';
    echo $this->Arg[$i];
    echo '<br />';
  }
}
public function __destruct(){}

}

$test1 = new variableArgs;
$test2 = new variableArgs("arg1");
$test3 = new variableArgs("arg1", "arg2");
$test4 = new variableArgs("arg1", "arg2", "arg3");

$test1->showArgs();
$test2->showArgs();
$test3->showArgs();
$test4->showArgs();

This outputs the following:

showArgs() called
$i: 0
No arguments passed
showArgs() called
$i: 0
arg1
showArgs() called
$i: 0
arg1
$i: 1
arg2
showArgs() called
$i: 0
arg1
$i: 1
arg2
$i: 2
arg3

I have no idea how efficient this is, but it works at any rate.  Hopefully this helps someone.

1.10.2006 20:03
This is a simple thing to bear in mind but it's also easy to forget it.  When chaining object constructors and destructors, always remember to call the superclass __construct() method in the subclass __construct() so that all superclass members are properly initialized before you start initializing the ones belonging to your subclass. 

Also, you will usually want to do your own cleanup first in your subclass __destruct() method so you will probably want to call the superclass __destruct() as the last thing in your subclass so that you can use resources defined in the superclass during the cleanup phase.

For example, if your superclass includes a database connection and your subclass __destruct method commits things to the database then if you call the superclass destruct before doing so then the database connection will no longer be valid and you will be unable to commit your changes.
chanibal at deltasoft dot int dot pl dot SPAMPROTECT
21.08.2006 6:56
Note that if a class contains another class, the contained class's destructor will be triggered after the destructor of the containing class.

<?php
class contained {
 
 protected
$parent;

 public function
__construct(&$p) {
 
# $this->parent=&$p;
 
}
 
 public function
__destruct() {
 
/* unset $this->parent */
 
print 'contained ';
  }
 }
 
class
containing {

 protected
$contained;

 public function
__construct() {
 
$this->contained=new contained($this);
  }

 public function
__destruct() {
 
// unset($this->contained);
 
print 'containing ';
  }
 }
 
 
new
containing();
?>

Will output
containing contained

After uncommenting the // comment, the output will change to
contained containing

Adding a reference from the contained class to the containing one (the # comment) will not change that, but beware, because it can cause random errors in other destructors in the parts of the script which seem unrelated! (PHP Version 5.1.2)
prauscher at gmx dot net
14.08.2006 13:05
I saw no note in the manual about my function. If you want to write a file in a __destruct - function, it will fail with a "Permission denied" Error.
Reza Mahjourian
10.07.2006 23:18
Peter has suggested using static methods to compensate for unavailability of multiple constructors in PHP.  This works fine for most purposes, but if you have a class hierarchy and want to delegate parts of initialization to the parent class, you can no longer use this scheme.  It is because unlike constructors, in a static method you need to do the instantiation yourself.  So if you call the parent static method, you will get an object of parent type which you can't continue to initialize with derived class fields.

Imagine you have an Employee class and a derived HourlyEmployee class and you want to be able to construct these objects out of some XML input too.

<?php
class Employee {
   public function
__construct($inName) {
      
$this->name = $inName;
   }

   public static function
constructFromDom($inDom)
   {
      
$name = $inDom->name;
       return new
Employee($name);
   }

   private
$name;
}

class
HourlyEmployee extends Employee {
   public function
__construct($inName, $inHourlyRate) {
      
parent::__construct($inName);
      
$this->hourlyRate = $inHourlyRate;
   }

   public static function
constructFromDom($inDom)
   {
      
// can't call parent::constructFromDom($inDom)
       // need to do all the work here again
      
$name = $inDom->name// increased coupling
      
$hourlyRate = $inDom->hourlyrate;
       return new
EmployeeHourly($name, $hourlyRate);
   }

   private
$hourlyRate;
}
?>

The only solution is to merge the two constructors in one by adding an optional $inDom parameter to every constructor.
Peter Molnar
18.05.2006 15:24
There were many notes about the inability of defining multiple constructors for the class.

My solution is to define separate static methods for each type of constructor.
<?php
class Vector {
    private
$x;
    private
$y;

    public function
__construct() {
       
$this->x = 0;
       
$this->y = 0;
    }

    public static function
createXY($x, $y) {
       
$v = new Vector();
       
$v->x = $x;
       
$v->y = $y;
        return
$v;
    }
}
?>
ckoschmied at web dot de
7.04.2006 16:58
Be aware of the fact that if you create a new instance of a class like this:

$instance = new Class();

$instance will not contain a valid reference to the newly created object until the constructor is finished. So don't use $instance while the constructor is still running.

Well, on the other side, why would you want to do it? I wanted to, and it took me some hours to figure out.
Even though it's quite obvious if you think about it :-)
jcaplan at bogus dot amazon dot com
24.03.2006 18:52
__construct and __destruct must be declared public in any class that you intend to instantiate with new.   However, in an abstract (or never-instantiated base) class you can declare them private or protected, and subclasses can still refer to them via parent::__construct (!) (tested in PHP 5.1.2).

9.02.2006 19:55
(Refering to: caliban at darklock dot com)

To force a constructor always to be called, and still be able to define a constructor on a derived class use the model below. Ideal for module architectures, because you only have to know the file and classname to construct an object.

<?php
class Parameter {}

abstract class
BaseClass
{
    protected
$param;
   
    public final function
__construct( Parameter $param )
    {
       
$this->param = $param;
       
$this->pseudoConstruct();
    }
   
    protected abstract function
pseudoConstruct();
}

class
ConcreteClass extends BaseClass
{
    protected function
pseudoConstruct()
    {
        echo
__CLASS__.' constructor';
    }
}

$refl = new ReflectionClass( 'ConcreteClass' );
if( !
$refl->isSubclassOf( 'BaseClass' ) ) throw new Exception( 'Invalid base class!' );
$refl->newInstance( new Parameter() );
?>
jochem AT mondrian-it d_o_t nl
30.01.2006 13:07
at: derk AT oneindig DOT com

You can achieve identical functionality by doing this:
<?php
class Parent {
   function
__construct()
   {
       echo
"Parent constructor called\\n";
   }
}

class
Child extends Parent {
   function
__construct()
   {
      
parent::__construct();
       echo
" Child 'contructor' called";
   }
}

$c = new Child();
?>
Added advantage is that Parent doesn't need to have the method myConstruct(), and that you're using constructors like they were intended.
developit at mail dot ru
25.01.2006 11:32
as [kida at keymail dot it] said you can't weaken a visibility of constructor when extending some class. but suggested trick that uses both old and new constructor namimg syntaxes to weaken visibility from 'protected' to 'public' seems a little bit odd. allthough it works allright. declaring extended class as 'abstract' with 'public' constructor will do quite the same thing in a more elegant manner and without any syntax mess.

<?php
class A
{
  public function
__construct()
  {
   
//do smth
 
}
}

abstract class
B extends A
{
  public function
__construct()
  {
   
parent::__construct();
  }
}
?>

thus, you avoid instanciating class B as if it had a protected contructor
aya at eh dot org
1.12.2005 11:20
For those who aren't already aware, PHP5 currently suffers from the classic reference counting leak. See http://en.wikipedia.org/wiki/Reference_counting for more info.

Example code:

<?php

   
class Noisy
   
{
        private
$name;

        public function
__construct($name)
        {
           
$this->name = $name;
            echo
"Noisy::__construct($this->name)\n";
        }

        public function
__destruct()
        {
            echo
"Noisy::__destruct($this->name)\n";
        }
    }
           
    function
foo($num)
    {
       
$noisy = new Noisy($num);
       
//$noisy->me = $noisy; // Uncomment this line to create a cyclic reference
   
}

    for (
$i = 0; $i < 10; ++$i)
       
foo($i);

?>

As it stands, the destructor of class 'Noisy' will be called on '$noisy' when it goes out of scope in function 'foo', but uncommenting the second line in function 'foo' will prevent this, and cause a memory leak.

See http://bugs.php.net/bug.php?id=33595 for a bug report, which reads as if this is not likely to get fixed in the near future, so watch out!
derk AT oneindig DOT com
3.11.2005 23:02
If a constructor is not present in a child class, php5 will try to call a constructor from the parent class. This behaviour can be used to somewhat simulate constructor chaining.

<?php
abstract class Parent {
    function
__construct()
    {
        echo
"Parent constructor called\n";
       
$this->myConstruct();
    }
}

class
Child extends Parent {
    function
myConstruct()
    {
        echo
" Child 'contructor' called";
    }
}

$c = new Child();
?>

will output:
Parent constructor called
Child 'constructor' called
contact at tcknetwork dot com
21.09.2005 9:54
be careful while trying to access files with __destruct() because the base directory (getcwd()) will be the root of your server and not the path of your script, so add before all your path called in __destruct() :
EITHER   dirname($_SERVER["SCRIPT_FILENAME"])."my/path/"
OR      dirname(__FILE__)."my/path/"
         (be careful with includes, it will give the path of the file processed and not the main file)
php dot net at lk2 dot de
13.08.2005 18:50
It looks like `echo()`ed output from the __destructor() function is displayed onto screen _before_ other output that the class may have have already sent before.

This can be misleading if you have debug info printed in the destructor but not a problem if you know it.
stanley dot turnteen at gmail dot com
5.08.2005 21:43
IMHO using func_get_args() is superior to constructor polymorphism, because you don't have to define constructors for every possible way a class can be initialized.

The pattern I use looks like this;  all you have to do is pass the parameters in the correct order.

<?php

 
class Movie
 
{
    public
$title;
    public
$director;
    public
$stars;
    public
$year_released;
   
    public function
__construct()
    {
     
$args = func_get_args();
     
      foreach(array(
"title", "director", "stars", "year_released") as $i)
      {
        if(empty(
$args))
        {
          break;
        }
       
       
$this->$i = array_shift($args);
      }
    }
   
  }
?>
dominics at gmail dot com
11.07.2005 4:12
If you're using E_STRICT error reporting, PHP will tell you if you define both __construct() and an old-style constructor (a function with the same name as the class) together in a class. Note that this occurs even if the old constructor function is abstract or final (for instance, if you were intending to only use it in a sub-class). Be wary of this if you're trying to implement the 'command' design pattern.

The solution? Either turn E_STRICT off (and possibly forgo some other important notices), rename your function (and possibly make things a little more complicated), or look at using an interface.
rocco at bluora dot com dot au
17.04.2005 5:29
Before PHP reaches the point where it calls the __destruct functions, it has already done a session_write_close() so you can no longer write anything to the session.

I wanted it to copy some variables from my class into the session once the script had finished but now having to get the last function to call a SaveToSession() function.

In php versions 5.0.2 and 5.0.4
contact at tcknetwork dot com
15.04.2005 17:45
Note that php5 use in priority __construct() instead of [classname](). So you could build a constructed/destructed class for php4/5 very easily using this.
<?
class test {
 function
test() {
 
$this->__construct();
 
register_shutdown_function(array($this,"__destruct"));
 }
 function
__construct() {
  echo
"construct\n";
 }
 function
__destruct() {
  echo
"destruct\n";
 }
};
$t=new test();
?>
In case you use unset($t) in php4, the destructor is not called. so be careful.
apfelsaft
30.03.2005 11:59
at the end of a script all remaining objects aren't in fact destructed. it is only their __destruct() method, which will be called. the objects still exist after that.

so, if your database connection object has no __destruct() or at least it doesn't disconnects the database, it will still work.

in general, there is no need to disconnect the database (especially for persistent connections).

5.03.2005 0:48
> To caliban at darklock dot com: Why not just define
> a dummy constructor

Because you don't always get to modify your base classes. Once you get beyond the "build to suit" range of software development, you end up having to work with other people's code, and sometimes you just plain can't change it. When Bob is in charge of making changes to that object, you can't add a dummy constructor. You have to tell Bob to do it, and until Bob does it, you don't get it. So if you want to hit your deadlines, you don't count on Bob caring enough about your job to make the changes you want... you work around it. It might be convenient for *you* to have a constructor on that object, but when you're only one of several thousand people that are using it, your convenience isn't generally among the design criteria.

Smaller projects where you can add whatever you want wherever you want will not have this problem, in which case the dummy constructor is indeed a better solution.

24.02.2005 10:08
To caliban at darklock dot com: Why not just define a dummy constructor <?PHP function __construct() {} ?> in the base class? This adds little overhead, and allows you to both extend the class worry-free and later add construct functionality to the base class.

And now, about destructors: I haven't seen this clarified anywhere in the manual, but object destructors are called implicitly at script shutdown for all objects that still exist at that Tpoint. his happens *after* any shutdown functions set with <?PHP register_shutdown_function() ?> have been called.

Objects appear to be destructed in the order they were defined, which means you have to be careful with destruct methods that rely on the functionality of other objects (e.g. on a database-handler) as they will have shut down already.



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)