54

I have this code. Is it possible for a User object constructor to somehow fail so that $this->LoggedUser is assigned a NULL value and the object is freed after constructor returns?

$this->LoggedUser = NULL;
if ($_SESSION['verbiste_user'] != false)
  $this->LoggedUser = new User($_SESSION['verbiste_user']);    
3
  • 7
    Great first question by the way. Commented Feb 6, 2010 at 21:20
  • I've seen a certain popular CMS that returns FALSE in a constructor. What's up with that?!?! Commented Oct 31, 2011 at 3:17
  • 1
    Just thought I'd chime in here for documentation sake. Since the date is so far back, it is possible that the CMS you are seeing was built for PHP4. PHP4 used to allow a lot of bad things, not the least of which allowed the user to overwrite $this in the named constructor (for example $this = false). Commented Dec 31, 2014 at 22:52

6 Answers 6

67

Assuming you're using PHP 5, you can throw an exception in the constructor:

class NotFoundException extends Exception {}

class User {
    public function __construct($id) {
        if (!$this->loadById($id)) {
             throw new NotFoundException();
        }
    }
}

$this->LoggedUser = NULL;
if ($_SESSION['verbiste_user'] != false) {
    try {
        $this->LoggedUser = new User($_SESSION['verbiste_user']);
    } catch (NotFoundException $e) {}
}

For clarity, you could wrap this in a static factory method:

class User {
    public static function load($id) {
        try {
            return new User($id);
        } catch (NotFoundException $unfe) {
            return null;
        }
    }
    // class body here...
}

$this->LoggedUser = NULL;
if ($_SESSION['verbiste_user'] != false)
    $this->LoggedUser = User::load($_SESSION['verbiste_user']);

As an aside, some versions of PHP 4 allowed you to set $this to NULL inside the constructor but I don't think was ever officially sanctioned and the 'feature' was eventually removed.

Sign up to request clarification or add additional context in comments.

3 Comments

+1 IMO, this is the correct OO way of indicating failure to construct an object.
It depends on the nature of the failure. If it was an exception, yes. If a parameter to the constructor did not meet a criterion, in my mind no.
Pekka, I'm not sure what sorts of "bad parameters" would not be an exception? If you can't create a valid object with a certain set of params surely that is exceptional, and should throw an exception? Can you give an example to clarify the distinction you're thinking of? (I see you do in the answer below, that would be useful up here, but I can't edit your comment!)
13

AFAIK this can't be done, new will always return an instance of the object.

What I usually do to work around this is:

  • Adding a ->valid boolean flag to the object that determines whether an object was successfully loaded or not. The constructor will then set the flag

  • Creating a wrapper function that executes the new command, returns the new object on success, or on failure destroys it and returns false

-

function get_car($model)
      {
        $car = new Car($model);
        if ($car->valid === true) return $car; else return false;
     } 

I'd be interested to hear about alternative approaches, but I don't know any.

3 Comments

Thanks for clarifying. So basically I could justwrap the new command in try...catch and then raise an exception in a constructor?
Good question! I think you can, but it doesn't really sound right to me. If I create an object car with model "Ford" it could simply be that no car of that model is in the database. That is not really what exceptions were designed for. It's more of an expected condition. I'd be interested to see what other answers come up, what is seen as the "right" way to handle this.
this is doing thing in the dirty way, check @jaz303's answer
6

Consider it this way. When you use new, you get a new object. Period. What you're doing is you have a function that searches for an existing user, and returns it when found. The best thing to express this is probably a static class function such as User::findUser(). This is also extensible to when you're deriving your classes from a base class.

1 Comment

That sounds the most logical, yes. I've only just begun OO programming in PHP so I'm not completely sure how to handle things in a 'proper' way.
5

A factory might be useful here:

class UserFactory
{
    static public function create( $id )
    {
        return (
            filter_var( 
                $id,
                FILTER_VALIDATE_INT, 
                [ 'options' => [ 'min_range' => 1, ] ]
            )
                ? new User( $id )
                : null
        );
  }
}

Comments

4

When a constructor fails for some unknown reason, it won't return a NULL value or FALSE but it throws an exception. As with everything with PHP5. If you don't handle the exception then the script will stop executing with an Uncaught Exception error.

2 Comments

When does a constructor throw an exception? When it returns false? Or do you mean, a constructor should throw an exception if a certain condition could not be met`?
Your constructor should throw the exception.
3

maybe something like this:

class CantCreateException extends Exception{
}

class SomeClass {
    public function __construct() {
       if (something_bad_happens) {
          throw ( new CantCreateException());
       }
    }
}

try{
  $obj = new SomeClass();
}
catch(CantCreateException $e){
   $obj = null;
}
if($obj===null) echo "couldn't create object";
//jaz303 stole my idea an wrap it into a static method

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.