在 PHP 中执行多个构造函数的最佳方法
您不能在 PHP 类中放置两个具有唯一参数签名的 __construct 函数。我想这样做:
class Student
{
protected $id;
protected $name;
// etc.
public function __construct($id){
$this->id = $id;
// other members are still uninitialized
}
public function __construct($row_from_database){
$this->id = $row_from_database->id;
$this->name = $row_from_database->name;
// etc.
}
}
在 PHP 中执行此操作的最佳方法是什么?
You can't put two __construct functions with unique argument signatures in a PHP class. I'd like to do this:
class Student
{
protected $id;
protected $name;
// etc.
public function __construct($id){
$this->id = $id;
// other members are still uninitialized
}
public function __construct($row_from_database){
$this->id = $row_from_database->id;
$this->name = $row_from_database->name;
// etc.
}
}
What is the best way to do this in PHP?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
我可能会做这样的事情:
然后,如果我想要一个我知道 ID 的学生:
或者如果我有一个 db 行数组:
从技术上讲,你不是在构建多个构造函数,只是构建静态辅助方法,但你可以这样可以避免构造函数中出现大量意大利面条式代码。
I'd probably do something like this:
Then if i want a Student where i know the ID:
Or if i have an array of the db row:
Technically you're not building multiple constructors, just static helper methods, but you get to avoid a lot of spaghetti code in the constructor this way.
Kris 的解决方案非常好,但我更喜欢工厂和流利风格的混合:
The solution of Kris is really nice, but I prefer a mix of factory and fluent style:
PHP 是一种动态语言,因此不能重载方法。您必须像这样检查参数的类型:
PHP is a dynamic language, so you can't overload methods. You have to check the types of your argument like this:
现在 $paramters 将是一个值为“One”、“Two”、3 的数组。
编辑,
我可以添加这
将为您提供函数参数的数量。
Now $paramters will be an array with the values 'One', 'Two', 3.
Edit,
I can add that
will give you the number of parameters to the function.
正如此处所示,在 PHP 中声明
多个
构造函数的方法有很多种,但没有一种是正确的
方法(因为 PHP 在技术上不支持允许)。但这并不能阻止我们破解这个功能......
这是另一个示例:
来源: 最简单的方法使用和理解多个构造函数:
希望这会有所帮助。 :)
As has already been shown here, there are many ways of declaring
multiple
constructors in PHP, but none of them are thecorrect
way of doing so (since PHP technically doesn't allow it).But it doesn't stop us from hacking this functionality...
Here's another example:
Source: The easiest way to use and understand multiple constructors:
Hope this helps. :)
你可以这样做:
You could do something like this:
从版本 5.4 开始,PHP 支持 traits。这不正是您正在寻找的,但是一种基于特征的简单方法是:
我们最终得到两个类,每个类对应一个构造函数,这有点适得其反。为了保持理智,我将添加一个工厂:
所以,一切都可以归结为:
这是一种极其冗长的方法,但它非常方便。
As of version 5.4, PHP supports traits. This is not exactly what you are looking for, but a simplistic trait based approach would be:
We end up with two classes, one for each constructor, which is a bit counter-productive. To maintain some sanity, I'll throw in a factory:
So, it all comes down to this:
It's a horribly verbose approach, but it can be extremely convenient.
这是一种优雅的方法。创建在给定参数数量的情况下启用多个构造函数的特征。您只需将参数数量添加到函数名称“__construct”中即可。所以一个参数将是“__construct1”,两个“__construct2”......等等。
Here is an elegant way to do it. Create trait that will enable multiple constructors given the number of parameters. You would simply add the number of parameters to the function name "__construct". So one parameter will be "__construct1", two "__construct2"... etc.
另一种选择是在构造函数中使用默认参数,如下所示
这意味着您需要使用如下所示的行进行实例化:
$student = new Student($row['id'], $row)
但保持你的构造函数美观和干净。另一方面,如果您想利用多态性,那么您可以创建两个类,如下所示:
Another option is to use default arguments in the constructor like this
This means you'll need to instantiate with a row like this:
$student = new Student($row['id'], $row)
but keeps your constructor nice and clean.On the other hand, if you want to make use of polymorphism then you can create two classes like so:
正如其他评论中所述,由于 php 不支持重载,因此通常会避免构造函数中的“类型检查技巧”,而使用工厂模式
。
as stated in the other comments, as php does not support overloading, usually the "type checking tricks" in constructor are avoided and the factory pattern is used intead
ie.
您可以执行如下操作,这非常简单且非常干净:
You could do something like the following which is really easy and very clean:
这个问题已经用非常聪明的方法来满足要求,但我想知道为什么不退一步问一个基本问题:为什么我们需要一个具有两个构造函数的类?
如果我的类需要两个构造函数,那么我设计类的方式可能需要更多的考虑才能得出更干净、更可测试的设计。
我们试图将实例化类的方式与实际的类逻辑混合起来。
如果 Student 对象处于有效状态,那么它是否是根据 DB 行或 Web 表单或 cli 请求中的数据构造的,这重要吗?
现在回答这里可能出现的问题,如果我们不添加从数据库行创建对象的逻辑,那么我们如何从数据库数据创建对象,我们可以简单地添加另一个类,称之为 StudentMapper if您对数据映射器模式感到满意,在某些情况下您可以使用 StudentRepository,如果没有任何东西适合您的需求,您可以创建一个 StudentFactory 来处理各种对象构造任务。
底线是当我们处理域对象时,不要将持久层放在我们的脑海中。
This question has already been answered with very smart ways to fulfil the requirement but I am wondering why not take a step back and ask the basic question of why do we need a class with two constructors?
If my class needs two constructors then probably the way I am designing my classes needs little more consideration to come up with a design that is cleaner and more testable.
We are trying to mix up how to instantiate a class with the actual class logic.
If a Student object is in a valid state, then does it matter if it was constructed from the row of a DB or data from a web form or a cli request?
Now to answer the question that that may arise here that if we don't add the logic of creating an object from db row, then how do we create an object from the db data, we can simply add another class, call it StudentMapper if you are comfortable with data mapper pattern, in some cases you can use StudentRepository, and if nothing fits your needs you can make a StudentFactory to handle all kinds of object construction tasks.
Bottomline is to keep persistence layer out of our head when we are working on the domain objects.
我知道我来得太晚了,但我想出了一个相当灵活的模式,应该允许一些非常有趣和多功能的实现。
像平常一样设置您的类,使用您喜欢的任何变量。
当你让你的对象只是传递一个关联数组,数组的键与你的变量的名称相同,就像这样......
这个实例化之后的
print_r($sample_variable);
产生以下结果:MyClass Object ( [myVar1:protected] => [myVar2:protected] => 123 )
因为我们已经在
中将
,也可以不将任何内容传递到构造函数中,就像这样...$group
初始化为 null __construct(...)现在输出完全符合预期:
MyClass Object ( [myVar1:protected] = > [myVar2:protected] => )
我写这个的原因是为了我可以直接将 json_decode(...) 的输出传递给我的构造函数,而不必担心关于它太多了。
这是在 PHP 7.1 中执行的。享受!
I know I'm super late to the party here, but I came up with a fairly flexible pattern that should allow some really interesting and versatile implementations.
Set up your class as you normally would, with whatever variables you like.
When you make your object just pass an associative array with the keys of the array the same as the names of your vars, like so...
The
print_r($sample_variable);
after this instantiation yields the following:MyClass Object ( [myVar1:protected] => [myVar2:protected] => 123 )
Because we've initialize
$group
to null in our__construct(...)
, it is also valid to pass nothing whatsoever into the constructor as well, like so...Now the output is exactly as expected:
MyClass Object ( [myVar1:protected] => [myVar2:protected] => )
The reason I wrote this was so that I could directly pass the output of
json_decode(...)
to my constructor, and not worry about it too much.This was executed in PHP 7.1. Enjoy!
我在创建具有不同签名的多个构造函数时遇到了同样的问题,但不幸的是,PHP 没有提供直接的方法来执行此操作。然而,我找到了克服这个问题的技巧。希望也适用于你们所有人。
I was facing the same issue on creating multiple constructors with different signatures but unfortunately, PHP doesn't offer a direct method to do so. Howerever, I found a trick to overcome that. Hope works for all of you too.
这是我的看法(为 php 5.6 构建)。
它将查看构造函数参数类型(数组、类名、无描述)并比较给定的参数。最后给出的构造函数必须具有最少的特异性。举例:
结果:
如果没有找到构造函数,则可以将其删除并允许“空”构造函数,而不是终止异常。或者任何你喜欢的。
This is my take on it (build for php 5.6).
It will look at constructor parameter types (array, class name, no description) and compare the given arguments. Constructors must be given with least specificity last. With examples:
Result:
Instead of the terminating exception if no constructor is found, it could be remove and allow for "empty" constructor. Or whatever you like.
从 PHP 8 开始,我们可以使用命名参数:
通过适当的检查,可以排除无效的参数组合,以便创建的实例在构造函数末尾是有效的(但错误只会在运行时检测到)。
Starting with PHP 8 we can use named arguments:
With proper checking it is possible to rule out invalid combinations of arguments, so that the created instance is a valid one at the end of the constructor (but errors will only be detected at runtime).
让我在这里补充一下
我个人喜欢添加构造函数作为返回类(对象)实例的静态函数。以下代码是一个示例:
请注意,现在您可以像这样创建 Person 类的实例:
我从以下位置获取该代码:
http://alfonsojimenez.com/post/30377422731/multiple-constructors-in-php
Let me add my grain of sand here
I personally like adding a constructors as static functions that return an instance of the class (the object). The following code is an example:
Note that now you can create instance of the Person class like this:
I took that code from:
http://alfonsojimenez.com/post/30377422731/multiple-constructors-in-php
嗯,很惊讶我还没有看到这个答案,假设我会参加比赛。
您可以选择将选项分离到它们自己的类中,例如扩展 SplEnum。
Hmm, surprised I don't see this answer yet, suppose I'll throw my hat in the ring.
You can optionally separate the options into their own class, such as extending SplEnum.
对于php7,我也比较参数类型,你可以有两个参数数量相同但类型不同的构造函数。
使用方法:
For php7, I compare parameters type as well, you can have two constructors with same number of parameters but different type.
To use it:
更现代的方法:
您将不同的类混合为一个实体和实体。数据水化。
因此,对于您的情况,您应该有 2 个类:
另请注意,您应该使用已经提供自动实体水合作用的学说或其他 ORM。
您应该使用依赖注入来跳过手动创建像 StudentHydrator 这样的对象。
More modern aproach:
You are mixing seperate classes into one, entity & data hydration.
So for your case you should have 2 classes:
Also please note that you should use doctrine or other ORM that already provides automatic entity hydration.
And you should use dependency injection in order to skip mannualy creating objects like StudentHydrator.
Kris 的回答很棒,但作为 Buttle Butku 注释,
new static()
在 PHP 5.3+ 中将是首选。所以我会这样做(根据克里斯的答案修改):
用法:
我还发现 php.net OOP 文档中的一个有用示例。
Kris's answer is great, but as Buttle Butku commented,
new static()
would be preferred in PHP 5.3+.So I'd do it like this (modified from Kris's answer):
Usage:
I also found an useful example in php.net OOP document.
为了回应 Kris 的最佳答案(顺便说一句,它令人惊讶地帮助设计了我自己的类),这里有一个修改版本,供那些可能觉得有用的人使用。包括从任何列中进行选择以及从数组中转储对象数据的方法。干杯!
In response to the best answer by Kris (which amazingly helped design my own class btw), here is a modified version for those that might find it useful. Includes methods for selecting from any column and dumping object data from array. Cheers!
按数据类型调用构造函数:
Call constructors by data type:
您始终可以向构造函数添加一个名为 mode 之类的额外参数,然后对其执行 switch 语句...
此外,如果您想添加更多功能,您可以随时使用该方法向 switch 语句添加另一个 case,并且您还可以检查以确保有人发送了正确的内容 - 在上面的示例中,除了 C 之外的所有数据都正常,因为它被设置为“某事”,因此类中的错误标志被设置并返回控制权返回主程序以决定下一步要做什么(在示例中,我只是告诉它退出并显示错误消息“无效模式” - 但您也可以将其循环回来,直到找到有效数据)。
You could always add an extra parameter to the constructor called something like mode and then perform a switch statement on it...
Also with that method at any time if you wanted to add more functionality you can just add another case to the switch statement, and you can also check to make sure someone has sent the right thing through - in the above example all the data is ok except for C as that is set to "something" and so the error flag in the class is set and control is returned back to the main program for it to decide what to do next (in the example I just told it to exit with an error message "invalid mode" - but alternatively you could loop it back round until valid data is found).
我创建这个方法是为了让它不仅在构造函数上使用,而且在方法中使用:
我的构造函数:
我的 doSomething 方法:
两者都适用于这个简单的方法:
所以你可以声明
or
等等:)
使用时:
它将调用
__constructN
,您在其中定义了N
args,然后
$myObject-> doSomething($arg1, $arg2,..., $argM)
它将调用
doSomethingM
, ,您在其中定义了M
args;I created this method to let use it not only on constructors but in methods:
My constructor:
My doSomething method:
Both works with this simple method:
So you can declare
or
and so on :)
And when using:
it will call
__constructN
, where you definedN
argsthen
$myObject -> doSomething($arg1, $arg2,..., $argM)
it will call
doSomethingM
, , where you definedM
args;