你不能在一个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 5.6构建)。
它将查看构造函数参数类型(数组,类名,无描述)并比较给定的参数。构造函数必须在最后以最少的特异性给出。例子:
// demo class
class X {
public $X;
public function __construct($x) {
$this->X = $x;
}
public function __toString() {
return 'X'.$this->X;
}
}
// demo class
class Y {
public $Y;
public function __construct($y) {
$this->Y = $y;
}
public function __toString() {
return 'Y'.$this->Y;
}
}
// here be magic
abstract class MultipleConstructors {
function __construct() {
$__get_arguments = func_get_args();
$__number_of_arguments = func_num_args();
$__reflect = new ReflectionClass($this);
foreach($__reflect->getMethods() as $__reflectmethod) {
$__method_name = $__reflectmethod->getName();
if (substr($__method_name, 0, strlen('__construct')) === '__construct') {
$__parms = $__reflectmethod->getParameters();
if (count($__parms) == $__number_of_arguments) {
$__argsFit = true;
foreach ($__parms as $__argPos => $__param) {
$__paramClass= $__param->getClass();
$__argVar = func_get_arg($__argPos);
$__argVarType = gettype($__argVar);
$__paramIsArray = $__param->isArray() == true;
$__argVarIsArray = $__argVarType == 'array';
// parameter is array and argument isn't, or the other way around.
if (($__paramIsArray && !$__argVarIsArray) ||
(!$__paramIsArray && $__argVarIsArray)) {
$__argsFit = false;
continue;
}
// class check
if ((!is_null($__paramClass) && $__argVarType != 'object') ||
(is_null($__paramClass) && $__argVarType == 'object')){
$__argsFit = false;
continue;
}
if (!is_null($__paramClass) && $__argVarType == 'object') {
// class type check
$__paramClassName = "N/A";
if ($__paramClass)
$__paramClassName = $__paramClass->getName();
if ($__paramClassName != get_class($__argVar)) {
$__argsFit = false;
}
}
}
if ($__argsFit) {
call_user_func_array(array($this, $__method_name), $__get_arguments);
return;
}
}
}
}
throw new Exception("No matching constructors");
}
}
// how to use multiple constructors
class A extends MultipleConstructors {
public $value;
function __constructB(array $hey) {
$this->value = 'Array#'.count($hey).'<br/>';
}
function __construct1(X $first) {
$this->value = $first .'<br/>';
}
function __construct2(Y $second) {
$this->value = $second .'<br/>';
}
function __constructA($hey) {
$this->value = $hey.'<br/>';
}
function __toString() {
return $this->value;
}
}
$x = new X("foo");
$y = new Y("bar");
$aa = new A(array("one", "two", "three"));
echo $aa;
$ar = new A("baz");
echo $ar;
$ax = new A($x);
echo $ax;
$ay = new A($y);
echo $ay;
结果:
Array#3
baz
Xfoo
Ybar
如果没有找到构造函数,可以将其删除并允许构造函数为“空”,而不是终止异常。或者你喜欢什么都行。
我可能会这样做:
<?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 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;
}