PHP 抽象类,接口,抽象方法,静态方法
1.Abstract class(抽象类)
- 抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类。
- 抽象类不能被直接实例化。抽象类中只定义(或部分实现)子类需要的方法。子类可以通过继承抽象类并通过实现抽象类中的所有抽象方法,使抽象类具体化。
- 如果子类需要实例化,前提是它实现了抽象类中的所有抽象方法。如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
举例说明
abstract Class AbstractClass
{
abstract public function A();//这里不要携带body
abstract protected function B();//这里不要携带body
public function C(){}//这里要携带body
} class ClassA extends AbstractClass
{
public function A(){
echo "Hello,I'm A <br/>";
}
protected function B(){
echo "Hello,I'm B <br/>";
}
public function E()
{
echo "Hello,I'm E <br/>";
}
}
注意要点:
- 如果 AbstractClass实现了抽象方法 B() ,那么 ClassA 中 B() 方法的访问控制不能比 AbstractClass 中 B() 的访问控制更严格,也就是说:
1)、如果AbstractClass中B为Public,则ClassA中B只能为public
2)、如果AbstractClass中B为Protected,则ClassA中B只能为public或Protected
3)、注意,AbstractClass的抽象方法不能为Private
- 抽象方法与普通的方法不一样,它只是子类中普通方法的一个占位符(只是占个地主不启作用),没有任何代码,也没有"{}"包含,而是以";"结束的.
2.Interface(接口)
- 接口用关键字 interface 来声明。抽象类提供了具体实现的标准,而接口则是纯粹的模版。接口只定义功能,而不包含实现的内容。
- interface 是完全抽象的,只能声明方法,而且只能声明 public 的方法,不能声明 private 及 protected 的方法,不能定义方法体,也不能声明实例变量 。然而, interface 却可以声明常量变量 。但将常量变量放在 interface 中违背了其作为接口的作用而存在的宗旨,也混淆了 interface 与类的不同价值。如果的确需要,可以将其放在相应的 abstract class 或 Class 中。
- 任何实现接口的类都要实现接口中所定义的所有方法,否则该类必须声明为 abstract 。
- 一个类可以在声明中使用 implements 关键字来实现某个接口。这么做之后,实现接口的具体过程和继承一个仅包含抽象方法的抽象类是一样的。一个类可以同时继承一个父类和实现任意多个接口。 extends 子句应该在 implements 子句之前。 PHP 只支持继承自一个父类,因此 extends 关键字后只能跟一个类名。
- 接口不可以实现另一个接口,但可以继承多个
实例:
interface A
{
public function fA();
Public function fB();
}
interface B
{
public function fC();
Public function fD();
}
interface C extends A,B
{ }
class M implements C
{
public function fA(){ }
public function fB(){ }
public function fC(){ }
public function fD(){ }
}
3.Abstract Class与Interface的异同
相同点
- 两者都是抽象类,都不能实例化。
- interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法。
不同点
- interface 需要实现,要用 implements ,而 abstract class 需要继承,要用 extends 。
- 一个类可以实现多个 interface ,但一个类只能继承一个 abstract class 。
- interface 强调特定功能的实现,而 abstract class 强调所属关系。
- 尽管 interface 实现类及 abstract class 的子类都必须要实现相应的抽象方法,但实现的形式不同。 interface 中的每一个方法都是抽象方法,都只是声明的 (declaration, 没有方法体 ) ,实现类必须要实现。
而 abstract class 的子类可以有选择地实现。这个选择有两点含义:
a) abstract class 中并非所有的方法都是抽象的,只有那些冠有 abstract 的方法才是抽象的,子类必须实现。那些没有 abstract 的方法,在 abstract class 中必须定义方法体;
b) abstract class 的子类在继承它时,对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
- abstract class 是 interface 与 class 的中介。 abstract class 在 interface 及 class 中起到了承上启下的作用。一方面, abstract class 是抽象的,可以声明抽象方法,以规范子类必须实现的功能;另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可以定义自己的实例变量,以供子类通过继承来使用。
- 接口中的抽象方法前不用也不能加 abstract 关键字,默认隐式就是抽象方法,也不能加 final 关键字来防止抽象方法的继承。而抽象类中抽象方法前则必须加上 abstract 表示显示声明为抽象方法。
- 接口中的抽象方法默认是 public 的,也只能是 public 的,不能用 private , protected 修饰符修饰。而抽象类中的抽象方法则可以用 public , protected 来修饰,但不能用 private 。
引用与推荐阅读>> PHP中的 抽象类(abstract class)和 接口(interface)
4.Abstract关键字
abstract关键字用于定义抽象方法与抽象类。
抽象方法指:没有方法体的方法,具体就是在方法声明的时候没有{},而是直接分号结束。一般用abstract定义的方法被称为抽象方法。在interface中所有的方法都是抽象方法。
定义抽象方法形如:
abstract function func_name();
抽象类指:只要一个类里面有一个方法是抽象方法,那么这个类就定义为抽象类。抽象类同样用abstract关键字来定义。关于抽象类的概念,更多了解可以看上面的解释。
5.Final关键字
final关键字,如果父类中的方法被声明为final,则子类无法覆盖该方法,如果一个类被声明为final,则不能被继承。
6.Static关键字
static关键字用来定义静态方法和属性,也可以用来定义静态变量以及后期静态绑定。
- 静态方法和属性:
声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。在没有指定访问控制(public,private,protected)的时候,属性和方法默认public。
静态方法不需要通过对象即可调用,所以伪变量$this在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。
就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
代码说明:
\Libs\Foo.php
<?php
namespace Libs; class Foo
{
public static $my_static = 'foo';
public function staticFunc()
{
return self::$my_static;
}
}
\Libs\SonFoo.php
<?php
namespace Libs; class SonFoo extends Foo
{
public function sonStatic()
{
return parent::$my_static;
}
}
\Libs\UseFoo.php
<?php
namespace Libs; class UseFoo
{
static public function index()
{
$eof = "<br/>"; echo Foo::$my_static,1,$eof; //静态属性的调用方式 $foo = new Foo();
echo $foo->staticFunc(),2,$eof; echo $foo->my_static,3,$eof;//报错,因为不能使用->方式调用静态属性 echo $foo::$my_static,4,$eof; $newfoo = 'Libs\Foo';
echo $newfoo::$my_static,5,$eof;// As of PHP 5.3.0 echo SonFoo::$my_static,6,$eof; $sonfoo = new SonFoo();
echo $sonfoo->sonStatic(),7,$eof; }
}
调用
UseFoo::index();
结果:
foo1
foo2
( ! ) Strict standards: Accessing static property Libs\Foo::$my_static as non static in ......Libs\UseFoo.php on line 15 | ||||
---|---|---|---|---|
Call Stack | ||||
# | Time | Memory | Function | Location |
1 | 0.0008 | 244064 | {main}( ) | ..\index.php:0 |
2 | 0.0026 | 262624 | Libs\UseFoo::index( ) | ..\index.php:51 |
( ! ) Notice: Undefined property: Libs\Foo::$my_static in ......Libs\UseFoo.php on line15 | ||||
---|---|---|---|---|
Call Stack | ||||
# | Time | Memory | Function | Location |
1 | 0.0008 | 244064 | {main}( ) | ..\index.php:0 |
2 | 0.0026 | 262624 | Libs\UseFoo::index( ) | ..\index.php:51 |
3
foo4
foo5
foo6
foo7
- 使用静态变量:
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:
<?php
function test($id)
{
static $count=0;
echo "{$id}=>count is :".$count."<br/>";
$count++;
} test(1);
test(2);
test(3);
结果:
1=>count is :0
2=>count is :1
3=>count is :2
静态变量也提供了处理递归函数(递归函数是一种调用自己的函数)的方法。下面列出一个使用static变量完成递归的函数。
举个小例子
function test($end)
{
static $sum=0;
if($end>0){
$sum +=$end;
$end--;
test($end);
}
return $sum;
}
echo test(10);//输出55
注意注意注意!上面代码只是一个小例子,实际生产中千万不要这么来求和!!!
- 后期静态绑定:
自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。
准确说,后期静态绑定工作原理是存储了在上一个“非转发调用”(non-forwarding call)的类名。当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。所谓的“转发调用”(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。可用 get_called_class() 函数来得到被调用的方法所在的类名,static:: 则指出了其范围。
该功能从语言内部角度考虑被命名为“后期静态绑定”。“后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。
1).self:: 使用self::或者__CLASS__对之前类的静态引用,取决于定义当前方法所在的类
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
} class B extends A {
public static function who() {
echo __CLASS__;
}
} B::test();//输出A
2).static:: 后期静态绑定本想通过引入一个新的关键字表示运行时最初调用的类来绕过限制。简单地说,这个关键字能够让你在上述例子中调用 test() 时引用的类是 B 而不是 A。最终决定不引入新的关键字,而是使用已经预留的 static 关键字。
//简单用法
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期静态绑定从这里开始
}
} class B extends A {
public static function who() {
echo __CLASS__;
}
} B::test();//输出B
在非静态环境下,所调用的类即为该对象实例所属的类,由于$this-> 会在同一作用范围内尝试调用私有方法,而static::则可能给出不同结果。static::只能用于静态属性
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
} class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
} class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
} $b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>
success!
success!
success! Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用 parent:: 或者 self:: 将转发调用信息。
class A {
public static function foo() {
static::who();
} public static function who() {
echo __CLASS__."\n";
}
} class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
} public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
} C::test();//输出结果为ACC
推荐阅读>>
abstract class和interface有什么区别?
PHP 抽象类,接口,抽象方法,静态方法的更多相关文章
- PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化)/约束类型/魔术方法小结
前 言 OOP 学习了好久的PHP,今天来总结一下PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化). 1 PHP中的抽象 ...
- java抽象类、抽象方法、接口、实现接口详解
对于java中的抽象类,抽象方法,接口,实现接口等具体的概念就不在这里详细的说明了,网上书本都有很多解释,主要是我懒,下面通过一个例子来说明其中的精髓要点,能不能练成绝世武功,踏上封王之路,就看自己的 ...
- PHP面向对象(抽象类与抽象方法、接口的实现)
一.抽象类与抽象方法 1,任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的. 2,定义为抽象的类不能被实例化. 3, 被定义为抽象的方法只是声明了其调用方式(参数) ...
- PHP的抽象类和抽象方法以及接口总结
PHP中的抽象类和抽象方法自己用的不多,但是经常会在项目中看到别人使用,同样,今天在看别人的代码的时候,发现使用了抽象类,就总结下: 抽象类:1.如果一个类中有一个方法是抽象方法,则这个类就是抽象类: ...
- 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait
[源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...
- 抽象类 接口 虚函数(C++模拟,个人见解)
1.抽象类里面可以有非抽象方法但接口里只能有抽象方法声明方法的存在而不去实现它的类被叫做抽像类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实 ...
- 【Java基础】【09面向对象_多态&抽象类&接口】
09.01_面向对象(多态的概述及其代码体现) A:多态(polymorphic)概述 事物存在的多种形态 B:多态前提 a:要有继承关系. b:要有方法重写. c:要有父类引用指向子类对象. C:案 ...
- -1-2 java 面向对象基本概念 封装继承多态 变量 this super static 静态变量 匿名对象 值传递 初始化过程 代码块 final关键字 抽象类 接口 区别 多态 包 访问权限 内部类 匿名内部类 == 与 equal
java是纯粹的面向对象的语言 也就是万事万物皆是对象 程序是对象的集合,他们通过发送消息来相互通信 每个对象都有自己的由其他的对象所构建的存储,也就是对象可以包含对象 每个对象都有它的类型 也就是 ...
- python 全栈开发,Day21(抽象类,接口类,多态,鸭子类型)
一.昨日复习 派生方法和派生属性 super 只有在子父类拥有同名方法的时候, 想使用子类的对象调用父类的方法时,才使用super super在类内 : super().方法名(arg1,..) 指名 ...
- 06 面向对象:多态&抽象类&接口&权限修饰符&内部类
多态: /* 多态(polymorphic)概述 * 事物存在的多种形态 多态前提 * a:要有继承关系. * b:要有方法重写. * c:要有父类引用指向子类对象. * 成员变量 * 编译看左边(父 ...
随机推荐
- AHOI2018 (暨HNOI2018)编外滚粗记
Day0: 向老师打了声报告就偷偷摸摸溜出了学校……感谢门卫师傅没把我当贼抓起来 车上背了一遍FFT,SAM的板子.嘴巴ac了两道CC水题.离线刷了一波知乎. 酒店好评. Day1: 不知不觉就开考了 ...
- CUBLAS基础实验
一.概述 最近在试图进行cuda并行编程,目标是编写一段矩阵计算代码,将计算结果存储进入GPU的缓冲区当中,并在达到某些要求后强制刷新缓冲区,取得计算结果. 但是考虑时间紧任务重的状况和实际的性能要求 ...
- python--基本类型之列表
Lest(列表): 定义和创建列表: 列表:是python以及其他语言中最常用的数据结构之一.python用 [] 来解析列表列表是可变的.--可以改变列表的内容可以用切片 a=['张三','李四', ...
- Spring常用注解用法总结
转自http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Dispat ...
- Captcha 验证码Example
maven依赖 防止和spring中的servlet冲突 <dependency> <groupId>com.github.penggle</groupId> &l ...
- z 变换
1. z 变换 单位脉冲响应为 \(h[n]\) 的离散时间线性时不变系统对复指数输入 \(z^n\) 的响应 \(y[n]\) 为 \[ \tag{1} y[n] = H(z) z^{n}\] 式中 ...
- JavaScript Map数据结构
Array.prototype.remove = function (s) { for (var i = 0; i < this.length; i++) { if (s == this[i]) ...
- lintcode-84-落单的数 III
84-落单的数 III 给出2*n + 2个的数字,除其中两个数字之外其他每个数字均出现两次,找到这两个数字. 样例 给出 [1,2,2,3,4,4,5,3],返回 1和5 挑战 O(n)时间复杂度, ...
- Flink之状态之checkpointing
1.前言 在Flink中,函数和操作符都可以是有状态的.在处理每个消息或者元素时,有状态的函数都会储存信息,使得状态成为精密操作中关键的组成部分. 为了使状态能够容错,Flink会checkpoint ...
- click & copy
click & copy https://github.com/zenorocha/clipboard.js/issues/604 https://github.com/zenorocha/c ...