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的区别

abstract class和interface有什么区别?

深入分析PHP final关键字使用技巧

PHP抽象类

PHP 抽象方法与抽象类abstract关键字介绍及应用

PHP abstract final static 关键字

时间: 2024-11-05 19:04:34

PHP 抽象类,接口,抽象方法,静态方法的相关文章

抽象类-接口--抽象方法几点解释

//abstract class和interface有什么区别?含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象.含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的.abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,(抽象类中的普通方法,可以不必实现.)所以,不能有抽象构造方法或抽象静态方法.如果子类没有实现抽象父类中的所有抽 象方法,那么子类也必须定义

PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化)/约束类型/魔术方法小结

  前  言  OOP  学习了好久的PHP,今天来总结一下PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化). 1  PHP中的抽象类与抽象方法 1.什么是抽象方法?              没有方法体 {} 的方法,必须使用abstract 关键字修饰.这样的方,我们叫做抽象方法.                    abstract function say(); //    抽象方法 2.什么是抽象类?        

python 之浅谈接口的定义和抽象类以及抽象方法

#_*_ coding:utf-8 _*_ #知识点:接口的定义和抽象类以及抽象方法 ''' 1.抽象类式啥? 抽象类加上抽象方法就等于接口 2.接口的定义 含义1.别人给你暴露一个URL,然后调用这个URL 含义2.定义一个规范,不写具体实现,按照这个规范去实现相关功能,抽象类就是属于这种 ''' from abc import  ABCMeta, abstractmethod #定义一个抽象类 class Alert:     __metaclass__ = ABCMeta     @abs

C#中的继承 (继承、抽象类和抽象方法、接口)

最近在研究重构,所以对于类,接口这些研究的也比较多,然后看各种资料,只要我感觉到能学到东西,就记录下来,感觉是件有意义的事情. 一.继承 什么是继承:继承是允许重用现有类去创建新类的过程.分类的原则是一个类派生出来的子类具有这个类的所有非私有的属性.1.继承C#中的类:C#不支持多重继承,C#类始终继承自一个基类(如果未在声明中指定一个基类,则继承自System.Object).派生类继承基类的语法如下:using System;public class Person{//这是基类}public

接口、抽象类、抽象方法、虚方法总结

一.接口 1.定义 1.1.访问修饰符 interface 接口名{成员可以为属性.方法.事件.索引器} 1.2.示例代码 public delegate void DelInfo(int Id); public interface IInformation { //属性 int Id { get; set; } int[] ArrayInt { get; set; } //方法 void IGetInfo(); //事件 event DelInfo IDelInfo; //索引器 long t

抽象方法和抽象类 &amp; 接口

抽象方法 使用abstract修饰的方法,没有方法体,只有声明.定义的是一种"规范",就是告诉子类必须要给抽象方法提供具体的实现. 抽象类 包含抽象方法的类就是抽象类.通过abstract方法定义规范,然后要求子类必须定义具体实现.通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用. 抽象类的使用要点 有抽象方法的类只能定义成抽象类 抽象类不能实例化,即不能用new来实例化抽象类. 抽象类可以包含属性.方法.构造方法.但是构造方法不能用来new实例,只能用来被子类调用.

PHP面向对象(抽象类与抽象方法、接口的实现)

一.抽象类与抽象方法 1,任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的. 2,定义为抽象的类不能被实例化. 3, 被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现. 4,必须在子类中将抽象类的全部抽象方法全部实现才可以 <?php // 任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的. abstract class Person // 定义为抽象的类不能被实例化. { public $name;

虚函数/纯虚函数/抽象类/接口/虚基类

1.多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 在Java中,没有指针,就直接用父类实例化子类对象 多态性就是允许将子类类型的指针赋值给父类类型的指针,多态是通过虚函数实现的,多态可以让父类的指针有“多种形态”,这是一种泛型技术. 所谓泛型技术,就是试图使用不变的代码来实现可变的算法 2.虚函数 在基类的类定义中,定义虚函数的一般形式: Virtual 函数返回值类型 虚函数名(形参表){ 函数

Java 抽象类 接口

抽象抽象方法定义的格式:public abstract 返回值类型 方法名(参数);抽象类定义的格式:abstract class 类名 {} public abstract class Fu {//抽象类 public abstract void work();//抽象方法 public void eat() {//抽象类可以放普通类 System.out.println("吃饭"); } } public class Zi extends Fu{ public void work(

06 面向对象:多态&amp;抽象类&amp;接口&amp;权限修饰符&amp;内部类

多态: /* 多态(polymorphic)概述 * 事物存在的多种形态 多态前提 * a:要有继承关系. * b:要有方法重写. * c:要有父类引用指向子类对象. * 成员变量 * 编译看左边(父类),运行看左边(父类). * 成员方法 * 编译看左边(父类),运行看右边(子类).动态绑定 * 静态方法 * 编译看左边(父类),运行看左边(父类). * (静态和类相关,算不上重写,所以,访问还是左边的) * 只有非静态的成员方法,编译看左边,运行看右边 */ class Demo_Polym