ID: 39868
User updated by: jb at ez dot no
Reported By: jb at ez dot no
-Status: Bogus
+Status: Open
Bug Type: Unknown/Other Function
Operating System: Kubuntu 6.10
PHP Version: 5.2.0
New Comment:
> Your arguments are based on wrong assumption that object
> is created in
> __construct(). This is wrong, because __construct() is
> supposed to
> initialize it, the object itself is created by "new" and
> already exists
> in __construct().
> No bug here.
I'm very aware that the constructor does not
create/allocate the object and that the constructor is
used for initialization. And I never claimed that it did
so.
What I'm saying is that the constructor (ie.
initialization) is never called (which is correct since
there is an exception) and therefore the destructor (which
is uninitialization) should not be called.
ie. this expression:
$a = new Master( new Child() );
would become this (using fake opcodes).
1. allocate instance of Master as $0
2. allocate instance of Child as $1
3. call $1->__construct()
4. call $0->__construct( $1 );
the end of the script would then do:
5. if not initialized $1 goto 7
6. call $1->__destruct()
7. if not initialized $0 goto 9
8. call $0->__destruct()
9. free instance $1
10. free instance $0
Since line #3 gives an exception it will never do #4,
however the script ends and it performs the freeing of the
objects but not the destructor of Master since it never
called __construct.
An alternative would also be:
1. allocate instance of Child as $1
2. call $1->__construct()
3. allocate instance of Master as $0
4. call $0->__construct( $1 );
To avoid the Master object being allocated at all.
Whichever way is chosen the __destruct() should not be
called in any case.
If PHP is meant to work this way there is something
seriously wrong with its design and should be fixed.
And also to demonstrate the problem with a real-life
example, consider this PHP code:
class Master {
public function __construct( $child ) {
echo __CLASS__, "::__construct() [", get_class(
$this ), "]\n";
$this->child = $child;
}
public function __destruct() {
echo __CLASS__, "::__destruct() [", get_class(
$this ), "]\n";
$this->child->callByMaster();
}
}
class Child {
public function __construct() {
echo __CLASS__, "::__construct() [", get_class(
$this ), "]\n";
throw new Exception( "Child failure" );
}
public function __destruct() {
echo __CLASS__, "::__destruct() [", get_class(
$this ), "]\n";
}
public function callByMaster() {
echo __CLASS__, "::__callByMaster() is called [",
get_class( $this ), "]\n";
}
}
$a = new Master( new Child() );
You will now get a fatal error in the destruct:
Child::__construct() [Child]
Master::__destruct() [Master]
Notice: Undefined property: Master::$child in
construct2.php on line 9
Call Stack:
0.0003 1. {main}() construct2.php:0
0.0005 2. Master->__destruct() construct2.php:0
Fatal error: Call to a member function callByMaster() on a
non-object in construct2.php on line 9
Call Stack:
0.0003 1. {main}() construct2.php:0
0.0005 2. Master->__destruct() construct2.php:0
Now the only way to protect against this problem is to use
a boolean to set if __construct() was called. However that
means that programmer must take care of issues which PHP
itself should solve for him.
Previous Comments:
------------------------------------------------------------------------
[2006-12-19 10:56:41] [EMAIL PROTECTED]
Your arguments are based on wrong assumption that object is created in
__construct(). This is wrong, because __construct() is supposed to
initialize it, the object itself is created by "new" and already exists
in __construct().
No bug here.
------------------------------------------------------------------------
[2006-12-19 10:38:45] jb at ez dot no
I'm sorry but this is definitely not Bogus, changing back
to Open.
------------------------------------------------------------------------
[2006-12-19 09:59:37] jb at ez dot no
> You didn't read my reply, did you?
> "Master::__construct() is called, you don't see the
> output because the
> exception is thrown just before you print it."
I did read it, and I just think you misunderstood my
explanation.
If you see in Master::__construct() there is no exception
throwing, hence this constructor cannot throw any
exceptions. The throwing is done in the
Child::__construct() (which does not inherit the Master
class) and so it will not interfere with the constructor
of the Master class.
I don't see why PHP would call the constructor then
immediately stop it before it gets to the first line of
the constructor code.
Did you try to run this through a debugger (GDB) to verify
that the constructor is actually run?
------------------------------------------------------------------------
[2006-12-19 09:32:21] [EMAIL PROTECTED]
>You don't think it is a problem that the destructor (for
>Master) is called while the constructor (for Master) is
>never called?
You didn't read my reply, did you?
"Master::__construct() is called, you don't see the output because the
exception is thrown just before you print it."
------------------------------------------------------------------------
[2006-12-19 08:28:46] jb at ez dot no
You don't think it is a problem that the destructor (for
Master) is called while the constructor (for Master) is
never called?
In this example neither the constructor or the destructor
should be called since an exception is thrown in the Child
class, ie. the new Master() expression should never be
processed.
The problem seems to be that PHP actually allocates the
object for Master and then delays the call to construct
until the parameters are prepared (which makes sense,
except the allocation). Then when the exception is thrown
PHP will cleanup all variables/objects, it then sees the
allocated object and tries the destructor,
In a good object oriented language you would never call
the destructor unless the constructor was called and was
completed 100%.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
http://bugs.php.net/39868
--
Edit this bug report at http://bugs.php.net/?id=39868&edit=1