php 在类的构造函数中返回一个值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6849572/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Returning a value in constructor function of a class
提问by Anoosh Ravan
So far I have a PHP
class with the constructor
到目前为止,我有一个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;
}
}
the functionality of loadUser
is to look up the database for a particular email address.
When i set the identifier to some email that i'm sure it's not in the database; the first IF is get passed, and goes to the first ELSE. here the constructor should return FALSE; but instead, it returns an object of the class with all NULL values !
的功能loadUser
是在数据库中查找特定电子邮件地址。当我将标识符设置为某个电子邮件时,我确定它不在数据库中;第一个 IF 被通过,然后转到第一个 ELSE。这里构造函数应该返回 FALSE;相反,它返回一个包含所有 NULL 值的类对象!
how do i prevent this? thanks
我如何防止这种情况?谢谢
EDIT:
编辑:
thank you all for the answers. that was quite fast ! I see that the OOP way is to throw an Exception. So a throw one, my question changes that what should i do with the exception?? php.net's manual is pretty confusing !
谢谢大家的回答。那是相当快!我看到 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 !!
}
}
回答by erisco
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
}
回答by worenga
The constructor is suppose to create an object. Since in php booleans are not considered to be objects the only option is null. Otherwise use a workaround i.e. write a static method which creates the actual object.
构造函数假设创建一个对象。由于在 php 中布尔值不被视为对象,因此唯一的选项是 null。否则使用变通方法,即编写创建实际对象的静态方法。
public static function CheckAndCreate($identifier){
$result = self::loadUser();
if($result === true){
return new EmailClassNameHere();
}else{
return false;
}
}
回答by slepic
The best you can do is what Steve has suggested. Never create constructors that do any job other then assigning constructor parameters to the object properties, maybe create some default ones, but nothing else. Constructors are meant to create a fully functional object. Such an object must always work as expected after its instantiation. A user has email, name and probably some other properties. When you want to instantiate a user object, give all those properties to its constructor. Throwing exceptions is not a good way either. An exception is meant to be thrown under exceptional conditions. Asking for a user by email is nothing exceptional, even if you eventualy figure out that no such user exists. Exception could be for example if you ask for a user by email = '' (unless that is a regular state in your system, but id rather suggest emails to be null in those cases). To get all those properties for a user object you should have a factory (or a repository if you prefer) object (yes, an object - it is a bad practice to use static whatever) Private constructor is a bad practice either (you'll need a static method anyway and as i already stated, statics are very bad)
你能做的最好的事情就是史蒂夫的建议。永远不要创建除了将构造函数参数分配给对象属性之外的任何其他工作的构造函数,也许创建一些默认的,但没有别的。构造函数旨在创建一个功能齐全的对象。这样的对象在实例化后必须始终按预期工作。用户有电子邮件、姓名和可能的一些其他属性。当您想要实例化用户对象时,请将所有这些属性赋予其构造函数。抛出异常也不是一个好方法。异常意味着在异常情况下抛出。通过电子邮件询问用户没什么特别的,即使您最终发现不存在这样的用户。例如,如果您通过电子邮件 = '' 询问用户(除非这是您系统中的常规状态,但 id 建议在这些情况下电子邮件为空)。要获取用户对象的所有这些属性,您应该拥有一个工厂(或存储库,如果您愿意)对象(是的,一个对象 - 使用静态任何东西都是一种不好的做法)私有构造函数也是一种不好的做法(您将无论如何都需要一个静态方法,正如我已经说过的,静态非常糟糕)
so the result should be something like this:
所以结果应该是这样的:
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('[email protected]');
if($user === null) {
//show error or whatever you want to do in that case
} else {
//do the job with user object
}
See? no statics, no exception, simple constructors and very readable, testable and modificable
看?没有静态,没有例外,简单的构造函数和非常可读、可测试和可修改的
回答by Michael Berkowski
A constructor cannot return anything but the object it is attempting to create. If the instantiation doesn't complete properly, you'll be left with a class instance full of NULL
properties as you've discovered.
构造函数不能返回任何东西,但它试图创建的对象除外。如果实例化没有正确完成,您将留下一个充满NULL
您发现的属性的类实例。
If the object loads in an incomplete or error state, I would suggest setting a property to indicate that.
如果对象以不完整或错误状态加载,我建议设置一个属性来指示。
// 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";
}
}
When instantiating the object then, you can check if it has an error status:
然后在实例化对象时,您可以检查它是否具有错误状态:
$obj = new MyObject($identifier);
if (!empty($obj->error)) {
// something failed.
}
Another (perhaps better) alternative is to throw an exception in the constructor, and wrap the instantiation in a try/catch
.
另一种(也许更好)的替代方法是在构造函数中抛出异常,并将实例化包装在try/catch
.
回答by Steve
Why not simply pass the results into the constructor needed to build the object, rather than try to make the constructor fail sometimes?
为什么不简单地将结果传递给构建对象所需的构造函数,而不是有时尝试使构造函数失败?
Even if you could make it fail sometimes, you will still need to check after calling the constructor to ensure it actually didconstruct, and in those lines, you could just call the ->loadUser() and pass the results into the constructor.
即使有时您可能会使其失败,您仍然需要在调用构造函数后进行检查以确保它确实构造了,并且在这些行中,您可以调用 ->loadUser() 并将结果传递给构造函数。
A good hint someone one told me, "always give the constructor what it needs to build the object, don't make it go looking for it."
有人告诉我的一个很好的提示,“总是给构造函数它构建对象所需的东西,不要让它去寻找它。”
public function __construct ($emailInTheDatabase, $otherFieldNeeded)
{
$this->emailAddress = $emailInTheDatabase;
$this->otherField = $otherFieldNeeded;
}
回答by Al.G.
I'm really surprised that for 4 years none of the 22k viewers suggested creating private constructor and a method that attempts to create an object like this:
我真的很惊讶 4 年来 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
This way you get either an object or false (you can also make it return null). Catching both situations is now very easy:
这样你就可以得到一个对象或 false(你也可以让它返回 null)。抓住这两种情况现在很容易:
$user = User::attemptToCreate('[email protected]');
if(!$user) { // or if(is_null($user)) in case you return null instead of false
echo "Not logged.";
} else {
echo $user->name; // e.g.
}
You can test it right here: http://ideone.com/TDqSyi
您可以在此处进行测试:http: //ideone.com/TDqSyi
I find my solution more convenient to use than throwing and catching exceptions.
我发现我的解决方案比抛出和捕获异常更方便使用。
回答by Anoosh Ravan
thanks for all the comments and solutions. here is what i done to fix the problem: (i hope it helps others)
感谢所有评论和解决方案。这是我为解决问题所做的工作:(我希望它可以帮助其他人)
// 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;
}
}
回答by Nico
I wouldn't put too much in the construct. You should consider a static functin that create the User (factory) instead of putting everything in the constructor. Thus, you can still use your user object without having to call implicitly the load function. This will save you pain.
我不会在构造中投入太多。您应该考虑创建用户(工厂)的静态函数,而不是将所有内容都放在构造函数中。因此,您仍然可以使用您的用户对象,而无需隐式调用加载函数。这将节省您的痛苦。
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;
}
Sample usage:
示例用法:
$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
}