php-在类的构造函数中返回值

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

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

29447791671682017201728的功能是在数据库中查找特定的电子邮件地址。当我将标识符设置为某些电子邮件时,我确定它不在数据库中; 第一个IF被传递,并转到第一个ELSE。 这里的构造函数应该返回FALSE; 但是,它返回具有所有NULL值的类的对象!

我该如何预防? 谢谢

编辑:

谢谢大家的回答。 那太快了! 我看到OOP的方式是抛出异常。 因此,我的问题改变了,我应该如何处理异常?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 !!  
        }
    }
Anoosh Ravan asked 2020-06-29T19:50:39Z
8个解决方案
71 votes

构造函数不会获得返回值。 它们完全用于实例化该类。

在不调整您已经在做的事情的情况下,您可以考虑在此处使用异常。

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

现在,您可以以这种方式创建新用户。

try {
    $user = new User('user@example.com');
} catch (Exception $e) {
    // unable to create the user using that id, handle the exception
}
erisco answered 2020-06-29T19:50:56Z
8 votes

构造函数假设要创建一个对象。 由于在php中,布尔值不被视为对象,因此唯一的选择是null。 否则,请使用变通办法,即编写创建实际对象的静态方法。

public static function CheckAndCreate($identifier){
  $result = self::loadUser();
  if($result === true){
    return new EmailClassNameHere();
  }else{
    return false;
  }
}
worenga answered 2020-06-29T19:51:16Z
7 votes

您能做的最好的就是史蒂夫的建议。除了将构造函数参数分配给对象属性之外,不要创建执行任何工作的构造函数,不要创建一些默认参数,而别无其他。构造函数旨在创建功能齐全的对象。此类对象在实例化后必须始终按预期工作。用户具有电子邮件,姓名以及其他一些属性。当您要实例化用户对象时,请将所有这些属性提供给其构造函数。抛出异常也不是一个好方法。在异常情况下应抛出异常。通过电子邮件询问用户并不是什么例外,即使您最终发现不存在这样的用户。例如,如果您通过email =”来请求用户,则可能是例外(除非这是系统中的常规状态,但id则建议电子邮件在这些情况下为空)。要获得用户对象的所有这些属性,您应该有一个工厂(或存储库,如果您愿意的话)对象(是的,一个对象-无论如何使用静态方法都是不好的做法)私有构造函数也不是一个好习惯(无论如何,您都需要一个静态方法,正如我已经说过的,静态函数非常糟糕)

所以结果应该是这样的:

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
}

看啊 没有静态,没有异常,简单的构造函数以及非常易读,可测试和可修改的

slepic answered 2020-06-29T19:51:47Z
3 votes

构造函数只能返回尝试创建的对象,而不能返回任何东西。 如果实例化无法正确完成,您将发现一个拥有try/catch个属性的类实例。

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

// 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.
}

另一个(也许更好)的选择是在构造函数中引发异常,并将实例化包装在try/catch中。

Michael Berkowski answered 2020-06-29T19:52:21Z
2 votes

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

即使有时使它失败,您仍然需要在调用构造函数之后进行检查以确保它确实进行了构造,并且在这些行中,您只需调用-> loadUser()并将结果传递给构造函数即可。

有人告诉我,这是一个很好的提示:“总是向构造函数提供构建对象所需的内容,而不是让它去寻找它。”

public function __construct ($emailInTheDatabase, $otherFieldNeeded)
{
    $this->emailAddress = $emailInTheDatabase;
    $this->otherField = $otherFieldNeeded;
}
Steve answered 2020-06-29T19:52:50Z
0 votes

感谢您的所有评论和解决方案。 这是我为解决此问题所做的工作:(希望它对其他人有帮助)

// 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;
        }
    }
Anoosh Ravan answered 2020-06-29T19:53:10Z
0 votes

我不会在结构中投入太多。 您应该考虑使用静态函数来创建User(工厂),而不是将所有内容都放在构造函数中。 因此,您仍然可以使用用户对象,而不必隐式调用load函数。 这样可以减轻您的痛苦。

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
}
Nico answered 2020-06-29T19:53:34Z
0 votes

令我惊讶的是,四年来,没有一个22k的观看者建议创建私有构造函数和试图创建这样的对象的方法:

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

这样,您将得到一个对象或false(也可以使它返回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; // e.g.
}

您可以在此处进行测试:[http://ideone.com/TDqSyi]

我发现我的解决方案比抛出和捕获异常更方便使用。

Al.G. answered 2020-06-29T19:54:08Z
translate from https://stackoverflow.com:/questions/6849572/returning-a-value-in-constructor-function-of-a-class