为什么我不能在 PHP 中重载构造函数?

我已经放弃了在 PHP 中使构造函数超载的所有希望,所以我真正想知道的是 为什么

有什么原因吗?它是否创建了固有的坏代码?是广泛接受的语言设计不允许它,还是其他语言比 PHP 更好?

75659 次浏览

据我所知,PHP 中不允许构造函数重载,这仅仅是因为 PHP 开发人员没有包含这个功能——这是关于 PHP 的众多抱怨之一。

我听说过技巧和变通方法,但是缺少 OOP 意义上的真正重载。也许在未来的版本中,它将被包括在内。

您可以使用 variable arguments来产生同样的效果。如果没有强类型,在给定默认参数和所有其他“解决方案”的情况下,添加这些参数就没有多大意义

PHP 中确实不支持真正的重载。正如@瘟疫提到的,可以使用变量参数。有些人只是用各种各样的关联数组来克服这个问题。

I'm really no OOP expert, but as I understand it 超载 means the ability of a method to act differently depending in the parameters it receives as input. This is very much possible with PHP, you just don't declare the input types since PHP does not have strong typing, and all the overloading is done at runtime instead of compile time.

在 PHP 中不能重载任何方法。如果您希望能够在传递几种不同的参数组合时实例化 PHP 对象,那么可以使用带有私有构造函数的工厂模式。

例如:

public MyClass {
private function __construct() {
...
}


public static function makeNewWithParameterA($paramA) {
$obj = new MyClass();
// other initialization
return $obj;
}


public static function makeNewWithParametersBandC($paramB, $paramC) {
$obj = new MyClass();
// other initialization
return $obj;
}
}


$myObject = MyClass::makeNewWithParameterA("foo");
$anotherObject = MyClass::makeNewWithParametersBandC("bar", 3);

可以在构造函数中使用条件语句,然后执行任务。 艾格。

  class Example
{
function __construct($no_of_args)


{// lets assume 2
switch($no_of_args)
{
case 1:
// write your code
break;
case 2:
//write your 2nd set of code
break;
default:
//write your default statement
}
}
}


$object1 = new Example(1);  // this will run your 1st case
$object2 = new Example(2);  // this will run your 2nd case

诸如此类。

他们说:

<?php
class A
{
function __construct()
{
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}


function __construct1($a1)
{
echo('__construct with 1 param called: '.$a1.PHP_EOL);
}


function __construct2($a1,$a2)
{
echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
}


function __construct3($a1,$a2,$a3)
{
echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
}
}
$o = new A('sheep');
$o = new A('sheep','cat');
$o = new A('sheep','cat','dog');


// results:
// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog
?>

似乎每个人都很高兴,但对我来说,它没有工作..。 如果你让它工作,这是一种超载太..。

它将所有的参数传递给辅助函数构造函数..。

我认为我们也可以使用 带默认参数的构造函数作为 PHP 中构造函数重载的潜在替代品。

尽管如此,在 PHP 中不支持真正的构造函数重载还是令人遗憾的。

为了完整起见,我建议使用 流畅的界面。其思想是,通过将 return $this;添加到方法的末尾,可以将调用链接在一起。所以

$car1 = new Car('blue', 'RWD');
$car2 = new Car('Ford', '300hp');

(这根本行不通) ,你可以这样做:

$car = (new Car)
->setColor('blue')
->setMake('Ford')
->setDrive('FWD');

这样,您就可以精确地选择要设置的属性。在很多方面,它类似于在初始调用中传入一个选项数组:

$car = new Car(['make' => 'Ford', 'seats' => 5]);

PHP 手册: 函数参数,默认值

通过对函数参数使用默认值,我已经克服了这个问题。在 __constuct中,首先列出所需的参数。以通用表格 $param = null列出其后的可选参数。

class User
{
private $db;
private $userInput;


public function __construct(Database $db, array $userInput = null)
{
$this->db = $db;
$this->userInput = $userInput;
}
}

这可以举例说明如下:

$user = new User($db)

or

$user = new User($db, $inputArray);

这不是一个完美的解决方案,但是我已经通过将参数分离到 绝对强制参数中来完成这项工作,而不管对象是在什么时候构造的,作为一个组,还是在 optional parameters listed in order of importance中。

有用。

<?php
//php do not automatically call parent class constructor at all if child class has constructor so you have to call parent class constructor explicitly, however parent class constructor is called automatically if child class has no constructor
class MyClass
{
function construct1($value1)
{
echo "<br/> dummy constructor is called with 1 arguments and it is $value1";
}
function construct2($value1,$value2)
{
echo "<br/> dummy constructor is called with 2 arguments and it is $value1, $value2";
}
function construct3($value1,$value2,$value3)
{
echo "<br/> dummy constructor is called with 3 arguments and it is $value1, $value2 , $value3";
}
public function __construct()
{
$NoOfArguments = func_num_args(); //return no of arguments passed in function
$arguments = func_get_args();
echo "<br/> child constructor is called $NoOfArguments";
switch ($NoOfArguments) {
case 1:
self::construct1($arguments[0]);
break;
case 2:
self::construct2($arguments[0],$arguments[1]);
break;


case 3:
self::construct3($arguments[0],$arguments[1],$arguments[2]);
break;


default:
echo "Invalid No of arguments passed";
break;
}
}




}
$c = new MyClass();
$c2 = new MyClass("ankit");
$c2 = new MyClass("ankit","Jiya");
$c2 = new MyClass("ankit","Jiya","Kasish");

?>

<?php


class myClass {


public $param1 = 'a';
public $param2 = 'b';


public function __construct($param1 = NULL, $param2 = NULL) {


if ($param1 == NULL && $param2 == NULL) {
//                $this->param1 = $param1;
//                $this->param2 = $param2;
} elseif ($param1 == NULL && $param2 !== NULL) {
//                $this->param1 = $param1;
$this->param2 = $param2;
} elseif ($param1 !== NULL && $param2 == NULL) {
$this->param1 = $param1;
//                $this->param2 = $param2;
} else {
$this->param1 = $param1;
$this->param2 = $param2;
}


}


}


//    $myObject  = new myClass();
//    $myObject  = new myClass(NULL, 2);
$myObject  = new myClass(1, '');
//    $myObject  = new myClass(1, 2);


echo $myObject->param1;
echo "<br />";
echo $myObject->param2;


?>

当然,可以使用 _ _ call ()和 _ _ callStatic ()魔法方法重载 PHP 中的任何函数。 这有点棘手,但是实现可以完全满足您的要求。 下面是 PHP.net 官方网站上的资源:

Https://www.php.net/manual/en/language.oop5.overloading.php#object.call

下面是一个同时适用于静态和非静态方法的例子:

class MethodTest
{
public function __call($name, $arguments)
{
// Note: value of $name is case sensitive.
echo "Calling object method '$name' "
. implode(', ', $arguments). "\n";
}


/**  As of PHP 5.3.0  */
public static function __callStatic($name, $arguments)
{
// Note: value of $name is case sensitive.
echo "Calling static method '$name' "
. implode(', ', $arguments). "\n";
}
}


$obj = new MethodTest;
$obj->runTest('in object context');


MethodTest::runTest('in static context');  // As of PHP 5.3.0


And you can apply this to constructors by using the following code in the __construct():

$clsName = get_class($this);
$clsName->methodName($args);

很简单。 并且您可能希望实现 _ _ clone ()来使用您调用的方法复制类的克隆副本,而不需要在每个实例中调用的函数..。

添加这个答案是为了获得与当前 PHP 相关的完整性,因为 PHP 的后续版本,实际上可以在某种程度上重载构造函数。下面的代码将有助于理解,

<?php
class A
{
function __construct()
{
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}
   

function __construct1($a1)
{
echo('__construct with 1 param called: '.$a1.PHP_EOL);
}
   

function __construct2($a1,$a2)
{
echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
}
   

function __construct3($a1,$a2,$a3)
{
echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
}
}
$o = new A('sheep');
$o = new A('sheep','cat');
$o = new A('sheep','cat','dog');
?>

产出:

__construct with 1 param called: sheep
__construct with 2 params called: sheep,cat
__construct with 3 params called: sheep,cat,dog
 public function construct1($user , $company)
{
dd("constructor 1");
$this->user = $user;
$this->company = $company;
}


public function construct2($cc_mail , $bcc_mail , $mail_data,$user,$company)
{
dd('constructor 2');
$this->mail_data=$mail_data;
$this->user=$user;
$this->company=$company;
$this->cc_mail=$cc_mail;
$this->bcc_mail=$bcc_mail;
}


public function __construct()
{
$NoOfArguments = func_num_args(); //return no of arguments passed in function
$arguments = func_get_args();
switch ($NoOfArguments) {
case 1:
self::construct1($arguments[0]);
break;
case 5:
self::construct2($arguments[0],$arguments[1],$arguments[2],$arguments[3],$arguments[4]);
break;
default:
echo "Invalid No of arguments passed";
break;
}

在这种情况下,我建议使用接口:

interface IExample {


public function someMethod();


}


class oneParamConstructor implements IExample {


public function __construct(private int $someNumber) {


}


public function someMethod(){


}
}


class twoParamConstructor implements IExample {


public function __construct(private int $someNumber, string $someString) {


}


public function someMethod(){


}
}

比在你的代码:

function doSomething(IExample $example) {


$example->someMethod();


}


$a = new oneParamConstructor(12);
$b = new twoParamConstructor(45, "foo");


doSomething($a)
doSomething($b)