你不能在一个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中最好的方法是什么?
在创建具有不同签名的多个构造函数时,我也面临着同样的问题,但不幸的是,PHP没有提供直接的方法来这样做。然而,我发现了一个技巧来克服它。希望也适用于你们所有人。
<?PHP
class Animal
{
public function __construct()
{
$arguments = func_get_args();
$numberOfArguments = func_num_args();
if (method_exists($this, $function = '__construct'.$numberOfArguments)) {
call_user_func_array(array($this, $function), $arguments);
}
}
public function __construct1($a1)
{
echo('__construct with 1 param called: '.$a1.PHP_EOL);
}
public function __construct2($a1, $a2)
{
echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
}
public function __construct3($a1, $a2, $a3)
{
echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
}
}
$o = new Animal('sheep');
$o = new Animal('sheep','cat');
$o = new Animal('sheep','cat','dog');
// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog
从5.4版开始,PHP支持trait。这并不是你真正想要的,但基于特征的简单方法是:
trait StudentTrait {
protected $id;
protected $name;
final public function setId($id) {
$this->id = $id;
return $this;
}
final public function getId() { return $this->id; }
final public function setName($name) {
$this->name = $name;
return $this;
}
final public function getName() { return $this->name; }
}
class Student1 {
use StudentTrait;
final public function __construct($id) { $this->setId($id); }
}
class Student2 {
use StudentTrait;
final public function __construct($id, $name) { $this->setId($id)->setName($name); }
}
我们最终得到两个类,每个构造函数一个,这有点适得其反。为了保持理智,我将加入一个工厂:
class StudentFactory {
static public function getStudent($id, $name = null) {
return
is_null($name)
? new Student1($id)
: new Student2($id, $name)
}
}
所以,这一切都归结为:
$student1 = StudentFactory::getStudent(1);
$student2 = StudentFactory::getStudent(1, "yannis");
这是一个非常冗长的方法,但它可以非常方便。
让我在这里加一粒沙子
我个人喜欢将构造函数作为返回类(对象)实例的静态函数添加。代码示例如下:
class Person
{
private $name;
private $email;
public static function withName($name)
{
$person = new Person();
$person->name = $name;
return $person;
}
public static function withEmail($email)
{
$person = new Person();
$person->email = $email;
return $person;
}
}
注意,现在你可以像这样创建Person类的实例:
$person1 = Person::withName('Example');
$person2 = Person::withEmail('yo@mi_email.com');
我的代码来自:
http://alfonsojimenez.com/post/30377422731/multiple-constructors-in-php
我知道我在这方面非常晚,但我提出了一个相当灵活的模式,应该允许一些真正有趣和通用的实现。
像往常一样设置类,使用您喜欢的任何变量。
class MyClass{
protected $myVar1;
protected $myVar2;
public function __construct($obj = null){
if($obj){
foreach (((object)$obj) as $key => $value) {
if(isset($value) && in_array($key, array_keys(get_object_vars($this)))){
$this->$key = $value;
}
}
}
}
}
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...
$sample_variable = new MyClass([
'myVar2'=>123,
'i_dont_want_this_one'=> 'This won\'t make it into the class'
]);
print_r($sample_variable);
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...
$sample_variable = new MyClass();
print_r($sample_variable);
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!
嗯,很惊讶我还没有看到这个答案,假设我要参加竞选。
class Action {
const cancelable = 0;
const target = 1
const type = 2;
public $cancelable;
public $target;
public $type;
__construct( $opt = [] ){
$this->cancelable = isset($opt[cancelable]) ? $opt[cancelable] : true;
$this->target = isset($opt[target]) ? $opt[target] : NULL;
$this->type = isset($opt[type]) ? $opt[type] : 'action';
}
}
$myAction = new Action( [
Action::cancelable => false,
Action::type => 'spin',
.
.
.
]);
您可以选择将这些选项分离到它们自己的类中,例如扩展脾。
abstract class ActionOpt extends SplEnum{
const cancelable = 0;
const target = 1
const type = 2;
}