Constructor returning value?

Looking at the following code, I see the constructor is returning a value. I thought that constructors only return objects. Can someone tell me what am I missing?

public function __construct($username = null, $password = null){
        $urlLogin = "{$this->apiHost}/login/$username";

        $postData = sprintf("api_type=json&user=%s&passwd=%s",
                            $username,
                            $password);
        $response = $this->runCurl($urlLogin, $postData);

        if (count($response->json->errors) > 0){
            return "login error";    
        } else {
            $this->modHash = $response->json->data->modhash;   
            $this->session = $response->json->data->cookie;
            return $this->modHash;
        }
    }

Solution 1:

Indeed you are correct. Nothing can be done with the return value of a constructor (aside from using the Object it created).

So no, you aren't missing anything, it's the developer who wrote that code who is.

It is technically possible to use return values from constructors, if you call the function directly

$obj->__construct();

That would allow you to use the constructor's return value. However, that is highly uncommon and fairly not recommended.

Solution 2:

You can do whatever you want with the return value of a constructor, so it's not true that "Nothing can be done with the return value of a constructor (aside from using the Object it created)." The return value of a constructor is not the object "it" created. The constructor does not create objects (the new keyword does). The return value of a constructor is the same as that of any other function: whatever you choose to return. Further, it is also false that an object already has to exist in order to call its constructor. This is perfectly valid:

$parent_constructor_return_value = parent::__construct();

For example:

abstract class MyBase {
    function __construct () {
        return "Hello, world.";
    }
}
class MyDerived extends MyBase {
    function __construct () {
        echo parent::__construct();
    }
}
new MyDerived(); // prints "Hello, world."

While this is possible, I can't conceive of a scenario in which it would be best practice. After all, you could always call a method other than parent::__construct() to get your value, and all you lose is obscurity. I suppose it could be used as a way of error-handling--there are two other ways to accomplish the same thing:

  1. Throw Exceptions in the parent constructor and catch them in your derived constructor.
  2. Set properties in the parent constructor indicating that an error happened, and then check the state of those properties in the derived constructor.

If an error in a parent constructor is not exceptional, he might have decided to have the parent constructor return error values, rather than storing transient error information as object properties. Of course, then the only reason to name the parent's method __construct is if the parent class is not abstract but can itself be instantiated--but in that context, the returned error messages would never be seen. So, bad pattern; bad. Constructors are not intended to return values, which means you're opening an architectural can of worms by leveraging this mechanism.

Solution 3:

See this page: Returning a value in constructor function of a class

Read it:-

Constructors don't get return values; they serve entirely to instantiate the class.

Without restructuring what you are already doing, you may consider using an exception here.

public function __construct ($identifier = NULL)
{
  $this->emailAddress = $identifier;
  $this->loadUser();
}

private function loadUser ()
{
    // try to load the user
    if (/* not able to load user */) {
        throw new Exception('Unable to load user using identifier: ' . $this->identifier);
    }
}

Now, you can create a new user in this fashion.

try {
    $user = new User('[email protected]');
} catch (Exception $e) {
    // unable to create the user using that id, handle the exception
}

Solution 4:

A constructor returns nothing, but you can return from it (stopping the method execution at a point for some reason but the object can be created).