PHP 多态性
多态性源自希腊词Poly(意为多)和morphism(意为重要结构)。
多态性是描述面向对象编程模型的四个支柱之一,也被称为OOPs(面向对象编程)。它是一种OOP设计,使类能够执行或共享共同的接口具有不同功能。多态性的有用之处在于,不同类中编写的代码对其所属的类没有影响,因为它们的使用方式相同。不同类中执行相同任务的方法名称应相同。为了确保类遵循多态性原则,我们可以在抽象类或接口之间选择。
面向对象编程
- OOPs,也称为面向对象编程,是一种组织编程技术,用于围绕数据和对象而不是逻辑和函数来组合代码块。
- 在使用面向对象编程语言时创建的对象是具有特定特征和特性的数据字段。
- 面向对象编程主要关注开发人员创建的数据对象,他们需要对其进行操作以执行特定任务,而不是关注控制对象所需的逻辑。
- 这种编程方式非常适合具有非常高复杂性或需要频繁更新或定期维护的程序。
- 面向对象编程的一些其他好处包括代码可重用性、可扩展性和高效性。
OOP的基本原则包括:
- 数据封装
- 数据抽象
- 继承
- 多态性
PHP中的多态性
通常,多态性有两种类型
- 编译时多态性,也称为函数重载
- 运行时多态性,也称为函数重写
注意:PHP不支持编译时多态性,这意味着我们无法使用如函数重载和运算符重载等多态性属性,这在许多情况下非常有用。在本文中,将使用多态性的运行时属性,即函数重写,来教授整个多态性属性。
运行时多态性
运行时多态性意味着在运行时(而不是在编译时)做出决策,或者我们可以为一个超类执行多个子类型。函数重写是运行时多态性的一个示例。
函数重写 – 每当我们在派生类中创建一个具有相同特征的函数,即函数具有相同的名称、相同数量的参数和相同类型的参数作为其父类中的函数时,称为函数重写。
示例:使用运行时多态性
<!DOCTYPE html>
<html>
<body>
<?php
// class to show run time polymorphism
class new_Shape
// parent class to draw differeent shapes
{
function draw(){}
}
// class Circle to draw a circle
class Circle extends new_Shape
{
function draw()
{
print " the function executed properly and Circle has been drawn . </br> ";
}
}
// class triangle to draw a triangle
class Triangle extends new_Shape
{
function draw()
{
print " the function executed properly and Triangle has been drawn . </br> ";
}
}
// class Square to draw a square
class Square extends new_Shape
{
function draw()
{
print "the function executed properly and Square has been drawn . ";
}
}
Val=array(2);Val[0] = new Circle();
Val[1] = new Triangle();Val[2] = new Square();
for(i=0;i<3;i++)
{Val[$i]->draw();
}
?>
</body>
</html>
输出:
在上面的程序中,我们声明了一个基类或父类 new_shape() 。我们使用继承属性从父类继承了三个子类circle、Triangle和Square的属性。每个类都被提供了一个函数draw来展示如何使用运行时多态性,如你所见,父类只持有函数draw的声明,而不继承它的属性。现在为了调用这些类,我们创建了一个名称为 val 的长度为2的数组。
数组索引用于调用每个类的对象。为了运行数组,我们使用循环根据声明的数组长度来执行数组。数组索引将使用$i计算数组的长度,每次数组重复时,I的值将增加。在特定的数组位置上将调用一个新的类,程序将自动执行。
PHP的多态性类型
PHP可以使用两种不同的方式来使用多态性。PHP的多态性使用了PHP中预先提供的接口和抽象类来实现多态性的方法。
抽象类和接口是单继承编程语言(比如PHP)的特殊特性,其中多重继承是不可能的。它帮助开发者减少了PHP单继承属性的限制,并在层次结构中不同层级的不同类中自由重用代码。它们与类几乎相似,但不同于类的是,它们一贯地组织功能。不能单独初始化接口,这就是为什么必须与类一起使用它的原因。我们可以说这些是一种帮助开发者实现多重继承和多态性的类型,可以同时使用多个函数
使用接口的多态性
接口 - 接口几乎跟类相似。除此之外,它不能包含代码。接口可以声明参数和方法名,但只能声明它们,不能添加这些方法的内容。任何将要执行接口的类都应该执行接口描述的所有方法。
语法:
Interface parent - class {
Statement . . .
. . . . . . . .
{ Only function declaration
no function definition }
. . . . . . . .
. . . . . . . .
}
Class child - class extends parent - class {
Statement . . .
. . . . . . . .
{ function definition }
. . . . . . . .
. . . . . . . .
}
Class child - class extends parent - class {
Statement . . .
. . . . . . . .
. . . . . . . .
}
使用接口的多态性示例
<!DOCTYPE html>
<html>
<body>
<?php
interface Area {
public function calcArea();
}
class Circle implements Area {
private radius;
public function __construct(radius){
this -> radius =radius;
}
public function calcArea(){
return this -> radius *this -> radius * pi();
}
}
class Rectangle implements Area {
private width;
privateheight;
public function __construct(width,height){
this -> width =width;
this -> height =height;
}
public function calcArea(){
return this -> width *this -> height;
}
}
mycirc = new Circle(3);myrect = new Rectangle(3,4);
echo "the area of circle is ";
echo mycirc->calcArea();
echo "<br>";
echo "the area of rectangle is "; echomyrect->calcArea();
?>
</body>
</html>
输出结果:
在上面的程序中,我们声明了一个接口或者父类 area() 。我们使用 interface 属性,从父类继承属性给两个子类Circle和rectangle。每个类都有一个函数 Calcarea() 来展示如何使用接口方法来实现运行时多态性。正如你所看到的,父类只拥有函数的声明,而没有它的属性。
根据多态性的规则,计算过程的各种策略在这种情况下应该有相同的名称。现在,每当我们需要计算不同类的任务时,我们会调用一个名为calcTask()的函数,而不会太关注如何计算不同函数的任务的细节。唯一需要知道的是计算任务的函数名。
使用抽象类实现多态性
抽象类和方法是指父类有一个命名的方法,但是要求子类完成任务。它是一个包含至少一个抽象方法的类,它是一种只声明但不在代码中实现的方法。
abstract关键字通常用于定义抽象类:
在继承抽象类时,子类的名称和访问修饰符/参数应该与之相同或更少受限制。因此,如果抽象类被定义为protected,子类应该定义为protected或public。正如我们所知,私有函数无论如何都不能继承。同样,变量或声明的类型和数量应该相同。然而,子类可以拥有更多的声明变量或方法。
但是在继承抽象类时,它必须遵循以下原则:
- 子类应该被定义为相同的名称,并重新声明从父类继承的抽象方法。
- 子类应该被定义为相同或更少限制的访问修饰符。
- 声明的变量数量应该是相同的。然而,子类可以拥有更多的声明变量或方法。
语法:
Abstract parent - class {
Statement . . .
. . . . . . . .
Abstract function ()
. . . . . . . .
}
Child - class extends parent - class {
Statement . . .
. . . . . . . .
. . . . . . . .
}
示例:
<?php
abstract class Language
// parent class
{
abstract public function greet();
}
class English extends Language
// child class that will inherit the properties
{
public function greet()
{
return 'Hello!';
}
}
class Spanish extends Language
{
// child class that will inherit the properties
public function greet()
{
return 'Hola!';
}
}
class French extends Language
{
// child class that will inherit the properties
public function greet()
{
return 'Bonjour!';
}
}
function greeting(people)
{
foreach (people as person) {
echoperson->greet() . '<br>';
}
}
people = [
new English(),
new spanish(),
new French()
];
greeting(people);
?>
输出:
在上述程序中,我们声明了一个抽象类 Language ,这个抽象类包含一个抽象方法或抽象函数 greet() 。我们使用 extends 关键字从父类继承属性给三个子类 English, Spanish和French ,每个子类会返回不同的输出。随后我们声明了一个函数 greeting() ,它将接受一个数组作为输入,并自动调用greet函数。为了获取输出,我们声明了一个包含所有子类English, Spanish和French的对象数组(为了调用一个类或获取一个类的输出,我们必须创建该类的对象),并将对象作为参数传递给我们的greeting函数。