看起来PHP中的多态性真的是多态吗?

Pet*_*háč 22 php oop polymorphism programming-languages

试图弄清楚PHP是否支持方法重载,继承和多态等功能,我发现:

  • 它不支持方法重载
  • 它确实支持继承

但我不确定多态性.我发现这是谷歌搜索互联网:

我应该注意到,在PHP中,多态性并不是它应该的方式.我的意思是它确实有效,但由于我们的数据类型很弱,所以它不正确.

它真的是多态吗?

编辑 只是不能确定肯定是或旁边没有PHP supports polymorphism.我不愿意说:"PHP不支持多态",而实际上它确实如此.或相反亦然.

Pao*_*ino 32

class Animal {
    var $name;
    function __construct($name) {
        $this->name = $name;
    }
}

class Dog extends Animal {
    function speak() {
        return "Woof, woof!";
    }
}

class Cat extends Animal {
    function speak() {
        return "Meow...";
    }
}

$animals = array(new Dog('Skip'), new Cat('Snowball'));

foreach($animals as $animal) {
    print $animal->name . " says: " . $animal->speak() . '<br>';
}
Run Code Online (Sandbox Code Playgroud)

你可以随意标记它,但这看起来像我的多态.

  • 确定,但Animal接口没有指定会有一个speak()方法.所以我可以构造一个像新FPDF()的对象; 然后将其添加到动物阵列中.然后怎样呢?怎么会说()? (4认同)
  • @PeterPerháč我迟到了讨论,但我不会使用弱,不安全,不干净或任何其他限定词.所有这些都是相对的术语,这引出了"相对于什么?"的问题.它是PHP,您可以将此编码概念应用于PHP代码.而已.实现这个概念在PHP中与在C++中实现的不同 - 所以几乎所有其他方面都使用这两种语言.它们是不同的语言,所以当然它是不同的.更弱,更清洁,或更不安全意味着只有C++具有"真正的多态性",显然不是这种情况. (2认同)

far*_*zad 16

虽然PHP不支持方法重载你在其他语言中经历的方式,比如Java.但是你可以在PHP中使用方法重载,但定义方法是不同的.如果你想为给定的方法提供不同的功能,在PHP中使用不同的参数集,你可以这样做:

class myClass {
    public function overloadedMethod() {
        // func_num_args() is a build-in function that returns an Integer.
        // the number of parameters passed to the method.
        if ( func_num_args() > 1 ) {
            $param1 = func_get_arg(0);
            $param2 = func_get_arg(1);
            $this->_overloadedMethodImplementation2($param1,$param2)
        } else {
            $param1 = func_get_arg(0);
            $this->_overloadedMethodImplementation1($param1)
        }
    }

    protected function _overloadedMethodImplementation1($param1) {
        // code 1
    }

    protected function _overloadedMethodImplementation2($param1,$param2) {
        // code 2
    }
}
Run Code Online (Sandbox Code Playgroud)

可能会有更清洁的实施,但这只是一个样本.

PHP支持继承和接口.所以你可以使用它们进行多态性.你可以有这样的界面:

// file: MyBackupInterface.php
interface MyBackupInterface {
    // saves the data on a reliable storage
    public function saveData();
    public function setData();
}

// file: myBackupAbstract.php
require_once 'MyBackupInterface.php';
class MyBackupAbstract implements MyBackupInterface {
     protected $_data;
     public function setData($data) {
         $this->_data= $data;
     }
     // there is no abstract modifier in PHP. so le'ts avoid this class to be used in other ways
     public function __construct() {
          throw new Exception('this class is abstract. you can not instantiate it');
     }
}

// file: BackupToDisk.php
require_once 'MyBackupAbstract.php';
class BackupToDisk extends MyBackupAbstract {
     protected $_savePath;

     // implement other methods ...

     public function saveData() {
           // file_put_contents() is a built-in function to save a string into a file.
           file_put_contents($this->_savePath, $this->_data);
     }
}

// file: BackupToWebService.php
require_once 'MyBackupAbstract.php';
class BackupToWebService extends MyBackupAbstract {
     protected $_webService;
     // implement other methods ...

     public function saveData() {
           // suppose sendData() is implemented in the class
           $this->sendData($this->_data);
     }
}
Run Code Online (Sandbox Code Playgroud)

现在在您的应用程序中,您可以像这样使用它:

// file: saveMyData.php
// some code to populate $myData
$backupSolutions = array( new BackupToDisk('/tmp/backup') , new BackupToWebService('webserviceURL') );
foreach ( $backupSolutions as $bs ) {
    $bs->setData($myData);
    $bs->saveData();
}
Run Code Online (Sandbox Code Playgroud)

你是对的,PHP不是强类型语言,我们从来没有提到任何你的$ backupSolutions都是'MyBackupAbstract'或'MyBackupInterface',但这并不能阻止我们使用多态的本质,这与使用不同的功能不同同样的方法.


Vla*_*nea 7

PHP具有基于类的多态性,但缺乏实现基于参数的多态的正式机制.

基于类的多态性意味着您可以根据基类进行思考,并且调用的方法取决于最终的类.例如,如果您有各种类的对象数组(如Triangle和Circle),并且这些类中的每一个都扩展了相同的类Shape,则可以将您的数组视为仅仅是形状的集合.您可以循环遍历形状并调用每个形状的getArea()方法.多态性是调用getArea()方法取决于对象类的现象.如果您的形状是三角形,则调用Triangle :: getArea(),如果是圆形,则调用Circle :: getArea() - 即使您的代码不区分圆形和三角形,但将每个对象视为只是一个形状.相同的代码行导致执行不同的代码块,具体取决于对象的类.

基于参数的多态性是一些强类型语言的特征,其中可以在单个类中定义多个同名方法,前提是它们具有不同的参数; 然后调用哪个方法取决于提供的参数.您可以通过手动考虑方法中的参数类型,在PHP等弱类型语言中模拟基于参数的多态.这是jQuery为了实现多态API而做的,尽管JavaScript缺乏基于本地参数的多态性.

因此,如果通过"支持多态",你的意思是它提供了一种实现基于参数的多态的正式机制,答案是否定的.对于任何更广泛的解释,答案是肯定的.理所当然,基于类的多态性现象发生在每种面向对象的语言中; 对于执行隐式类型转换以实现基于参数的多态的语言没有意义.


Til*_*ill 6

__call()并且__callStatic()应该支持方法重载.有关详细信息,请参见手册.或者你究竟追求的是什么?

更新:我刚刚注意到其他回复.

有关重载方法的另一种方法,请考虑以下事项:

<?php
public function foo()
{
    $args = func_get_arg();
}
Run Code Online (Sandbox Code Playgroud)

当然不漂亮,但它允许你做任何你想要的事情.

  • "Homer的Tule Box"是Homer Simpson在他的工具箱上写的.:) (2认同)