在类的构造函数中返回一个值

到目前为止,我有一个PHP类的构造函数

 public function __construct ($identifier = NULL) { // Return me. if ( $identifier != NULL ) { $this->emailAddress = $identifier; if ($this->loadUser() ) return $this; else { // registered user requested , but not found ! return false; } } 

loadUser的function是查找特定电子邮件地址的数据库。 当我设置标识符到一些电子邮件,我敢肯定它不在数据库中; 第一个IF被通过,并且进入第一个ELSE。 这里的构造函数应该返回FALSE; 但相反,它将返回具有所有NULL值的类的对象!

我如何防止这个? 谢谢

编辑:

谢谢大家的答案。 这相当快! 我看到OOP的方式是抛出一个exception。 所以抛出一个,我的问题改变,我应该怎么做的exception? php.net的手册很混乱!

  // Setup the user ( we assume he is a user first. referees, admins are considered users too ) try { $him = new user ($_emailAddress); } catch (Exception $e_u) { // try the groups database try { $him = new group ($_emailAddress); } catch (Exception $e_g) { // email address was not in any of them !! } } 

构造函数不会得到返回值; 他们完全是为了实例化class级。

如果不重构已经在做的事情,您可以考虑在这里使用例外。

 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); } } 

现在,您可以用这种方式创build一个新用户。

 try { $user = new User('user@example.com'); } catch (Exception $e) { // unable to create the user using that id, handle the exception } 

构造函数是假设创build一个对象。 由于在PHP布尔不被认为是对象唯一的select是空的。 否则使用一种解决方法,即写一个静态方法,创build实际的对象。

 public static function CheckAndCreate($identifier){ $result = self::loadUser(); if($result === true){ return new EmailClassNameHere(); }else{ return false; } } 

构造函数不能返回任何东西,除了它正在尝试创build的对象。 如果实例化没有正确完成,那么您将会留下一个充满NULL属性的类实例,就像您发现的那样。

如果对象加载的不完整或错误状态,我会build议设置一个属性来表明这一点。

 // error status property public $error = NULL; public function __construct ($identifier = NULL) { // Return me. if ( $identifier != NULL ) { $this->emailAddress = $identifier; if (!$this->loadUser() ) { // registered user requested , but not found ! $this->error = "user not found"; } } 

当实例化对象时,可以检查它是否有错误状态:

 $obj = new MyObject($identifier); if (!empty($obj->error)) { // something failed. } 

另一个(也许更好的)替代方法是在构造函数中抛出exception,并将实例化包装在try/catch

你能做的最好的是史蒂夫build议的。 永远不要创build构造函数来完成任何其他工作,然后将构造函数参数分配给对象属性,也许创build一些默认的构造函数,但除此之外别无它法 构造函数是为了创build一个function齐全的对象。 这样的对象在实例化之后必须始终按预期工作。 用户有电子邮件,名称和其他一些属性。 当你想实例化一个用户对象时,把所有这些属性赋给它的构造函数。 抛出exception也不是一个好方法。 意外的是在特殊情况下抛出exception。 通过电子邮件询问用户是没有什么特别的,即使你最终发现没有这样的用户存在。 例外情况可能是,例如,如果您通过电子邮件=“'(除非这是您的系统中的常规状态,但是idbuild议电子邮件在这些情况下为空)请求用户。 要获得用户对象的所有这些属性,你应该有一个工厂(或者一个存储库,如果你愿意的话)对象(是的,一个对象 – 这是一个不好的做法,使用静态的任何)私人构造是一个不好的做法(你会无论如何需要一个静态方法,正如我已经说过,静态是非常糟糕的)

所以结果应该是这样的:

 class User { private $name; private $email; private $otherprop; public function __construct($name, $email, $otherprop = null) { $this->name = $name; $this->email = $email; $this->otherprop = $otherprop; } } class UserRepository { private $db; public function __construct($db) { $this->db = $db; //this is what constructors should only do } public function getUserByEmail($email) { $sql = "SELECT * FROM users WHERE email = $email"; //do some quoting here $data = $this->db->fetchOneRow($sql); //supose email is unique in the db if($data) { return new User($data['name'], $data['email'], $data['otherprop']); } else { return null; } } } $repository = new UserRepository($database); //suppose we have users stored in db $user = $repository->getUserByEmail('whatever@wherever.com'); if($user === null) { //show error or whatever you want to do in that case } else { //do the job with user object } 

看到? 没有静力学,没有例外,简单的构造,非常可读,可testing和可修改

为什么不简单地将结果传递给构build对象所需的构造函数,而不是尝试使构造函数有时失败?

即使你有时可能会失败,你仍然需要在调用构造函数之后检查它,确保它实际上构造的,在这些行中,你可以调用 – > loadUser()并将结果传递给构造函数。

有人告诉我一个很好的暗示:“总是给构造函数build立对象所需的东西,不要去找它。”

 public function __construct ($emailInTheDatabase, $otherFieldNeeded) { $this->emailAddress = $emailInTheDatabase; $this->otherField = $otherFieldNeeded; } 

感谢所有的意见和解决scheme。 这里是我所做的解决这个问题:(我希望它可以帮助别人)

 // Setup the user ( we assume he is a user first. referees, admins are considered users too ) try { $him = new user ($_emailAddress); // check the supplied password $pass_ok = $him->auth($_Password); // check the activation status $active_ok = $him->makeActive(); } catch (Exception $e_u) { // try the groups database try { $him = new group ($_emailAddress); // check the supplied password $pass_ok = $him->auth($_Password); //var_dump ($pass_ok); // check the activation status $active_ok = $him->makeActive(); } catch (Exception $e_g) { // email address was not in any of them !! $pass_ok = false; $active_ok = false; } } 

我不会在构造中放太多。 你应该考虑创build用户(工厂)的静态functin,而不是把所有东西放在构造函数中。 因此,您仍然可以使用您的用户对象,而无需隐式调用加载函数。 这会节省你的痛苦。

 public function __construct(){} public function setIdentifier($value){ $this->identifier = $value; } public function load(){ // whatever you need to load here //... throw new UserParameterNotSetException('identifier not set'); // ... // if user cannot be loaded properly throw new UserNotFoundException('could not found user'); } public static function loadUser($identifier){ $user = new User(); $user->setIdentifier($identifier); $user->load(); return $user; } 

示例用法:

 $user = new User(); try{ $user->setIdentifier('identifier'); $user->load(); } catch(UserParameterNotSetException $e){ //... } catch(UserNotFoundException $e){ // do whatever you need to do when user is not found } // With the factory static function: try{ $user2 = User::loadUser('identifier'); } catch(UserParameterNotSetException $e){ //... } catch(UserNotFoundException $e){ // do whatever you need to do when user is not found } 

我真的很惊讶,4年来没有一个22K的观众build议创build私人构造函数和一个方法,试图创build一个这样的对象:

 class A { private function __construct () { echo "Created!\n"; } public static function attemptToCreate ($should_it_succeed) { if ($should_it_succeed) { return new A(); } return false; } } var_dump(A::attemptToCreate(0)); // bool(false) var_dump(A::attemptToCreate(1)); // object(A)#1 (0) {} //! new A(); - gives error 

这样你可以得到一个对象或者是假的(你也可以让它返回null)。 捕捉这两种情况现在非常简单:

 $user = User::attemptToCreate('email@example.com'); if(!$user) { // or if(is_null($user)) in case you return null instead of false echo "Not logged."; } else { echo $user->name; // eg } 

你可以在这里testing它: http : //ideone.com/TDqSyi

我发现我的解决scheme比使用抛出和捕获exception更方便。