Edit report at http://bugs.php.net/bug.php?id=52330&edit=1

 ID:              52330
 User updated by: whistl0r+phpbug at googlemail dot com
 Reported by:     whistl0r+phpbug at googlemail dot com
 Summary:         __construct() method should always return a new
                  instance
 Status:          Wont fix
 Type:            Bug
 Package:         Class/Object related
 PHP Version:     Irrelevant

 New Comment:

> Basically, if you don't want __construct() to act like a method call,

> don't call it like a method call.



Well, why does PHP supports different visibilities like "public",
"protected" or "private"? You can tell the programmer, "don't read the
variable, it's private!" like you say "don't call it like a method". ;)



You support it, because it is part of the OOP concept (encapsulation).



Other languages like Java or C# doesn't allow you to call the
constructor like a method. The constructor is only callable with "new"
(because it's not a normal method).



Currently, to be safe from OOP view, it seems to me like you must add
something like



  protected $_initiated = false



to your class. If this is "true", your constructor method will end. This
would make sure, that the constructor will only run once and you object
cannot enter an unexpected state, because someone calls the constructor
again...


Previous Comments:
------------------------------------------------------------------------
[2010-07-13 18:34:08] ahar...@php.net

That might seem odd, but it seems consistent enough to me. It breaks
down one of two ways:



1. You call the constructor by instantiating an object with new. It
behaves like a constructor -- return values are ignored and a new object
instance is created.



2. You call the constructor by calling $object->__construct(). It
behaves like a method call, including return values being returned.



Basically, if you don't want __construct() to act like a method call,
don't call it like a method call.

------------------------------------------------------------------------
[2010-07-13 16:35:38] whistl0r+phpbug at googlemail dot com

Description:
------------
Please see the test script. This should be normal PHP 5.3 class with a
good OOP design.



In PHP it is possible, that I can call the constructor multiple times,
for example:



$person = new \My\Person('Jens', 'Mander');

echo sprintf('Name: %s %s', $person->getName(), $person->getSurname());
// Will output "Name: Jens Mander"



$person->__construct('John', 'Doe');

echo sprintf('Name: %s %s', $person->getName(), $person->getSurname());
// Will output "Name: John Doe"



In my understanding, it is unexpected, that

1) you can access the constructor method in an instantiated object. The
constructor should only instantiate the object - when you have the
object, there is no need to call it again. If you need something to
"reset" your object state, you should implement such a method.



2) If you can call the constructor again, that it will change the object
and *not* return a new instance.



For example:

If you add a "return new \stdClass();" line to your constructor, it will
still change the instance you called it from, but now it will also
return a "stdClass" - that's inconsistent, isn't it?

Test script:
---------------
<?php

namespace My;



class Person

{

  protected $_name = null;

  

  protected $_surname = null;

  

  /**

  * Constructor.

  * 

  * @param  string OPTIONAL $name

  * @param  string OPTIONAL $surname

  * @return \My\Person

  */

  public function __construct($name = null, $surname = null)

  {

    if ($name !== null)

    {

        $this->setName($name);

    }

    

    if ($surname !== null)

    {

        $this->setSurname($surname);

    }

  }

  

  /**

  * Returns the name.

  * 

  * @return null|string Null, when no name was set

  */

  public function getName()

  {

    return $this->_name;

  }

  

  /**

  * Returns the surname.

  * 

  * @return null|string Null, when no name was set

  */

  public function getSurname()

  {

    return $this->_surname;

  }

  

  /**

  * Set the name.

  * 

  * @param  string $name

  * @return \My\Person Provides fluent interface

  * @throws \Exception

  */

  public function setName($name)

  {

    if (!is_string($name) || empty($name))

    {

      throw new \Exception('Name cannot be empty and must be a
string!');

    }

    

    $this->_name = $name;

    

    

    return $this;

  }

  

  /**

  * Set the surname.

  * 

  * @param string $name

  * @return \My\Person Provides fluent interface

  * @throws \Exception When $name isn't a string or empty

  */

  public function setSurname($name)

  {

    if (!is_string($name) || empty($name))

    {

      throw new \Exception('Name cannot be empty and must be a
string!');

    }

    

    $this->_surname = $name;

    

    

    return $this;

  }

}

Expected result:
----------------
- FATAL error e.g. "Object already constructed!"



- The __construct() call should return a *new* object.

Actual result:
--------------
The __construct() method will work on the object, from where you called
it.


------------------------------------------------------------------------



-- 
Edit this bug report at http://bugs.php.net/bug.php?id=52330&edit=1

Reply via email to