搜索文章

输入标题或内容中的关键词。

← 回到技术手记
编程

PHP 学习笔记(三):类、继承、接口与抽象类

gemhack··11 分钟阅读

本文整理 PHP 基础学习笔记。涉及旧版行为的内容保留历史说明,运行时应按实际 PHP 版本核对。

类与方法

1.类

1.类的定义

class classname{
    修饰符 $属性名;
    修饰符 $属性名 = 默认值;//默认值可设
    ...
    修饰符 function 方法名{
        ...
    }
}

在类中有$this变量指向当前对象,调用自身属性的时候可以使用$this变量

class student{
    var name;
    public function read(){
        echo $this->name.'reading';
    }
}

2.类的使用

$obj = new classname;//如果构造方法中不含有参数,可以不加括号
$obj->属性/方法;//使用->调用属性和方法,属性和方法前没有$符号

2.访问控制

1.public

在类中使用public修饰的属性和方法在全局均可以访问,将属性设置为var也表示为public,方法设置为缺省也表示public,但是属性不可缺省,方法可缺省。

class student{
    var $name;
    public $no;//均表示public

    function read(){//该方法公有,可以在任何地方调用
        ...
    }
    public function listen(){//该方法公有,可以在任何地方调用
        do something...
    }
}

2.protected

使用protected修饰表示只能在本类,父类和子类中访问。

3.private

表示只能在本类访问。

4.static

用static修饰表示静态的,表示属于类公有的,使用static修饰的属性和方法可以直接通过对象名来调用,不必依赖对象,在类中调用自身静态属性和方法通常使用self::关键字,而在其他类或者在类外使用类名::调用。

class student{
    var $name;
    public static $no = 100;//均表示public

    function read(){//该方法公有,可以在任何地方调用
        ...
    }
    public function listen(){//该方法公有,可以在任何地方调用

        echo self::$no;
    }
}
echo student::$no;

在类中声明的常量为类常量,与静态变量的区别在于不需要加$,不可被修改。与全局常量的区别在于调用的时候需要加上类名::

3.构造函数与析构函数

类都有构造函数__construct(),缺省默认为无参,构造函数在对象创建的时候自动调用,完成对象的初始化,如果手动定义了构造函数,则默认的消失。构造函数不一定为 public;如果要在类外直接 new 对象,通常设为 public

class student{
    var $name;
    public $no;//均表示public

    public function __construct($name){
        $this->name = $name;
    }

    public function listen(){//该方法公有,可以在任何地方调用
        do something...
    }
}

类的析构函数__destruct(),在对象被销毁的时候自动调用,用于作销毁前的准备工作,释放资源,提醒等。

class student{
    var $name;
    public $no;//均表示public

    public function __construct($name){
        $this->name = $name;
    }
    public function listen(){//该方法公有,可以在任何地方调用
        do something...
    }
    function __destruct(){
        echo '类正在被销毁';
    }
}

4.类继承、重写、final关键字

使用extends关键字可以继承父类的所有属性和方法,包括私有的,但是无法访问私有属性和方法。这并不意味着没有继承下来,使用var_dump()可以发现全部继承下来了,但是父类中的私有属性和方法无法访问,只能通过父类中的公有方法和受保护的方法来访问。

class A{
    public $name;
    private $birth;
    public function __construct($name){
        $this->name = $name;
    }

}

class B extends A{
    public function say(){
        echo 'what can i say'.$this->birth;
    }
}

当父类中的属性和方法无法满足子类的实际需求的时候,可以对父类中的属性和方法重写,这时调用属性和方法会默认调用子类的。

class A{
    public $name;
    protected $no;
    private $birth;
    public function __construct($name){
        $this->name = $name;
    }
    function yes(){
        echo 'A is saying yes';
    }
}

class B extends A{
    protected $no = '452';

    function yes(){
        echo 'B is saying yes';
    }
    public function say(){
        echo 'what can i say'.$this->birth;
    }
}

使用final关键字修饰类,可以保证类不会被继承。

使用final修饰的方法不能被子类重写,但是还是会被子类继承。因为在php中子类会继承父类的所有属性和方法,包括私有的。

PHP 8.3 及更早版本不支持 final 属性;PHP 8.4 起支持。

5.调用父类的方法和属性、static延迟绑定

在子类中可以使用parent::关键字调用父类的属性和方法,在类中使用static::会动态绑定当前调用的类的静态属性和方法,与self::的不同之处在于self只会绑定当前类的静态属性或方法,当子类重写了静态属性和方法的时候,使用self不会调用子类重写的属性和方法,所以需要使用static,static会根据调用类的不同,调用当前类的静态变量。

class A{
    public $name;
    public static $birth = 2021;
    public function __construct($name){
        $this->name = $name;
    }
    final public function say(){
        echo self::$birth;
        echo 'what can i say1';
        echo static::$birth;
    }
}

class B extends A{
    public static $birth = 2022;
}
$o = new B('789');
$o->say();
//2021what can i say12022

07接口与抽象类

1.接口

使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。接口中定义的所有方法都必须是公有,这是接口的特性。要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

interface human{
    public function eat();
    public function walk();
}

class man implements human{
    public function eat(){
        echo 'I am eating';
    }
    public function walk(){
        echo 'I am walking';
    }
}

2.抽象类

任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。定义为抽象的类不能被实例化。

被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。

使用abstract class关键字定义抽象类,抽象方法也需要使用abstract修饰。

<?php
abstract class AbstractClass
{
 // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . PHP_EOL;
    }
}
class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') . PHP_EOL;
?>

参考资料

评论发表评论

评论

发表评论

邮箱不会公开。标有 * 的项目为必填项。