你不能在一个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中最好的方法是什么?
从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");
这是一个非常冗长的方法,但它可以非常方便。
我可能会这样做:
<?php
class Student
{
public function __construct() {
// allocate your stuff
}
public static function withID( $id ) {
$instance = new self();
$instance->loadByID( $id );
return $instance;
}
public static function withRow( array $row ) {
$instance = new self();
$instance->fill( $row );
return $instance;
}
protected function loadByID( $id ) {
// do query
$row = my_awesome_db_access_stuff( $id );
$this->fill( $row );
}
protected function fill( array $row ) {
// fill all properties from array
}
}
?>
然后,如果我想要一个学生,我知道ID:
$student = Student::withID( $id );
或者如果我有一个db行数组:
$student = Student::withRow( $row );
从技术上讲,您不需要构建多个构造函数,而只是静态帮助方法,但是这样可以避免构造函数中的大量意大利面条代码。
嗯,很惊讶我还没有看到这个答案,假设我要参加竞选。
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;
}
这里有一种优雅的方法。创建trait,在给定参数数量的情况下启用多个构造函数。你只需将参数的数量添加到函数名“__construct”中。所以一个参数是"__construct1",两个"__construct2"…等。
trait constructable
{
public function __construct()
{
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array([$this,$f],$a);
}
}
}
class a{
use constructable;
public $result;
public function __construct1($a){
$this->result = $a;
}
public function __construct2($a, $b){
$this->result = $a + $b;
}
}
echo (new a(1))->result; // 1
echo (new a(1,2))->result; // 3