我已经放弃在PHP中实现构造函数重载的希望,因此我真正想知道的是为什么。
这是否有原因?它会创建本质上糟糕的代码吗?不允许它是普遍接受的语言设计,还是其他语言比PHP更好些?
我已经放弃在PHP中实现构造函数重载的希望,因此我真正想知道的是为什么。
这是否有原因?它会创建本质上糟糕的代码吗?不允许它是普遍接受的语言设计,还是其他语言比PHP更好些?
在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);
MyClassFactory
对象,它有makeNewWithParameterA()
和makeNewWithParametersBandC()
方法而不是静态的,所以它们更适合于“依赖注入”框架。但如果你控制环境并且不想创建“工厂类”,那么这是最清洁的方式,就像@SamGiles所说的一样。使用相同构造函数和 switch-case 调用私有方法的解决方案是糟糕的代码。 - Xavi Montero你可以使用可变参数来实现相同的效果。由于没有强类型,因此添加默认参数和所有其他“解决方案”并不太有意义。
为了完整起见,我建议使用流畅接口(Fluent Interfaces)。这个想法是通过在你的方法末尾添加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]);
我通过在函数参数中使用默认值来解决这个问题。在__construct
中,首先列出必填参数,在此之后以一般形式$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)
或者
$user = new User($db, $inputArray);
这不是一个完美的解决方案,但我通过将参数分成绝对必要的参数和按重要性顺序列出的可选参数组来使其工作,虽然有些牵强。
它能运行。
在PHP中,真正的重载确实不受支持。正如@Pestilence所提到的,您可以使用可变参数。有些人只是使用各种选项的关联数组来克服这个问题。
<?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 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
?>
看起来每个人都对它感到满意,但对我来说却没有用...如果你让它起作用,它也会一种过载...
它会获取所有参数并将它们传递给次级函数构造器...
您可以在构造函数中使用条件语句,然后执行您的任务。 例如:
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
等等……
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)
为了完整性起见,我会提供与当前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