精华内容
下载资源
问答
  • 面向对象编程(Object-oriented Programming, OOP)是一种基于“对象”概念的编程范式,它可以包含字段(通常称为属性或属性)形式的数据,以及过程(通常称为方法)形式的代码。 FP 与 OOP 的区别 计算机著名...

    函数式编程(Functional Programming, FP)是一种编程范式——一种构建计算机程序结构和元素的方式,它将计算视为数学函数的评估,并避免改变状态和可变数据。

    面向对象编程(Object-oriented Programming, OOP)是一种基于“对象”概念的编程范式,它可以包含字段(通常称为属性或属性)形式的数据,以及过程(通常称为方法)形式的代码。

    FP 与 OOP 的区别

    计算机著名定论:

    程序 = 数据结构 + 算法

    无论什么编程范式,都必须处理数据结构和算法。让我们换种说法,把算法视作是某种逻辑行为,即‘程序 = 数据 + 行为’。

    OOP 会把数据和相关行为放到某个对象中处理,所谓的对象就是数据与行为的集合,是对现实某个实体的抽象,比起数据,对象更关心实体有哪些行为,像一些支持 OOP 的语言,比如 java,对象一般就是某个类的实例,实例中的数据一般不会暴露给外部代码,外部代码能接触到的只有实例提供的方法。

    比起 OOP,FP 则把数据和行为完全分开处理,比起行为,FP 更加关注数据结构是什么样的,怎么样由 A 数据衍生计算出 B 数据。FP 更适合数据结构稳定清晰的场景,数据驱动开发模式就是基于 FP 范式的。FP 带来的很大好处是数据不可变,由于数据不可变,开发者不用关心什么某个数据在什么时候什么条件下会改变。

    举个例子来说明两者的区别:作为一名老板,你需要给每个雇员加薪。

    OOP 模式:

    1. 构建一个雇员 Employee 类,初始化需要雇员的姓名 name 和工资 salary 信息。
    2. 给每个雇员实例化一个 Employee 实例。
    3. 通过 Employee 的 addSalary 方法给每个员工涨薪。
    // 雇员类
    class Employee {
        constructor(name, salary){
            this.name = name
            this.salary = salary
        }
        
        // 增加工资
        addSalary(pay) {
            this.salary += pay
        }
    }
    
    // 初始化所有员工
    const employees = [
        new Employee('jack', 1000),
        new Employee('john', 2000)
    ]
    
    // 给每个员工涨薪 1000
    employees.forEach(employee => {
        employee.addSalary(1000)
    })
    复制代码

    FP 模式:

    1. 新建一个包含雇员姓名 name 和工资 salary 的对象数组。
    2. 定义一个给所有员工涨薪的函数 addSalary
    3. 生成一个涨薪后的雇员信息数组。
    // 雇员信息数组
    const employees = [
        {name: 'jack', salary: 1000},
        {name: 'john', salary: 2000}
    ]
    
    // 涨薪函数
    function addSalary(employees, salary) {
        return employees.map(employee => ({...employee, salary: employee.salary + salary}))
    }
    
    // 生成涨薪后数组
    const newEmployees = addSalary(employees, 1000)
    复制代码

    对于这个例子来说,我们是围绕雇员这个概念来进行建模的,我们更关心的是雇员的涨薪动作(后续可能还有请假等动作)而不是雇员涨薪后的数据,因此从这个角度说,OOP 模式更适合这个场景。这个结论不是绝对的,还得看开发人员对两个范式的理解和掌握。

    参考资料

    展开全文
  • 我们需要保证代码具有高内聚低耦合,这里我们使用了OOP编程思想。 oop四大基本特性: 抽象:提取现实世界中某事物的关键特性,为该事物构建模型的过程。对同一事物在不同的需求下,需要提取的特性

    简单了解面向对象编程(oop)和常见的几种设计模式

    背景:

    1、软件设计开发过程中疑难问题:

    • 软件复杂庞大
    • 难以维护阶
    • 版本迭代需求变更

    软件设计开发中存在很多其他的问题,上面只是从程序开发和设计的角度看到的部分问题。需求解决上面软件开发中的问题,就要求我们编写(设计)的软件具有很好的可读性、可维护性和可扩展性。我们需要保证代码具有高内聚低耦合,这里我们使用了OOP编程思想。

    oop四大基本特性:

    • 抽象:提取现实世界中某事物的关键特性,为该事物构建模型的过程。对同一事物在不同的需求下,需要提取的特性可能不一样。得到的抽象模型中一般包含:属性(数据)和操作(行为)。这个抽象模型我们称之为类。对类进行实例化得到对象。

    • 封装:封装可以使类具有独立性和隔离性;保证类的高内聚。只暴露给类外部或者子类必须的属性和操作。类封装的实现依赖类的修饰符(public、protected和private等)

    • 继承:对现有类的一种复用机制。一个类如果继承现有的类,则这个类将拥有被继承类的所有非私有特性(属性和操作)。这里指的继承包含:类的继承和接口的实现。

    • 多态:多态是在继承的基础上实现的。多态的三个要素:继承、重写和父类引用指向子类对象。父类引用指向不同的子类对象时,调用相同的方法,呈现出不同的行为;就是类多态特性。多态可以分成编译时多态和运行时多态。

    24种设计模式:
    在这里插入图片描述
    常见的几种设计模式:

    1、构造函数模式

    /**
     * 构造一个动物的函数 
     */
    function Animal(name, color){
        this.name = name;
        this.color = color;
        this.getName = function(){
            return this.name;
        }
    }
    // 实例一个对象
    var cat = new Animal('猫', '白色');
    console.log( cat.getName() );
    

    2、工厂模式

    /**
     * 工厂模式
     */
    function Animal(opts){
        var obj = new Object();
        obj.name = opts.name;
        obj.color = opts.color;
        obj.getInfo = function(){
            return '名称:'+obj.name +', 颜色:'+ obj.color;
        }
        return obj;
    }
    var cat = Animal({name: '波斯猫', color: '白色'});
    cat.getInfo();
    

    3、模块模式

    /**
     * 模块模式 = 封装大部分代码,只暴露必需接口
     */
    var Car = (function(){
        var name = '法拉利';
        function sayName(){
            console.log( name );
        }
        function getColor(name){
            console.log( name );
        }
        return {
            name: sayName,
            color: getColor
        }
    })();
    Car.name();
    Car.color('红色');
    

    4、混合模式

    /**
     * 混合模式 = 原型模式 + 构造函数模式
     */
    function Animal(name, color){
        this.name = name;
        this.color = color;
        console.log( this.name  +  this.color)
    }
    
    Animal.prototype.getInfo = function(){
        console.log('名称:'+ this.name);
    }
    
    function largeCat(name, color){
        Animal.call(null, name, color);
        this.color = color;
    }
    
    largeCat.prototype = create(Animal.prototype);
    function create (parentObj){
        function F(){}
        F.prototype = parentObj;
        return new F();
    };
    
    largeCat.prototype.getColor = function(){
        return this.color;
    }
    var cat = new largeCat("Persian", "白色");
    console.log( cat )
    

    5、单例模式

    /**
     * 在执行当前 Single 只获得唯一一个对象
     */
    var Single = (function(){
        var instance;
        function init() {
            //define private methods and properties
            //do something
            return {
                //define public methods and properties
            };
        }
    
        return {
            // 获取实例
            getInstance:function(){
                if(!instance){
                    instance = init();
                }
                return instance;
            }
        }
    })();
    
    var obj1 = Single.getInstance();
    var obj2 = Single.getInstance();
    
    console.log(obj1 === obj2);
    

    6、发布订阅模式

    /**
     * 发布订阅模式
     */
    var EventCenter = (function(){
        var events = {};
        /*
        {
          my_event: [{handler: function(data){xxx}}, {handler: function(data){yyy}}]
        }
        */
        // 绑定事件 添加回调
        function on(evt, handler){
            events[evt] = events[evt] || [];
            events[evt].push({
                handler:handler
            })
        }
        function fire(evt, arg){
            if(!events[evt]){
                return 
            }
            for(var i=0; i < events[evt].length; i++){
                events[evt][i].handler(arg);
            }
        }
        function off(evt){
            delete events[evt];
        }
        return {
            on:on,
            fire:fire,
            off:off
        }
    }());
    
    var number = 1;
    EventCenter.on('click', function(data){
        console.log('click 事件' + data + number++ +'次');
    });
    EventCenter.off('click');   //  只绑定一次
    EventCenter.on('click', function(data){
        console.log('click 事件' + data + number++ +'次');
    });
    
    EventCenter.fire('click', '绑定');
    
    展开全文
  • 基于ROS2的POP和OOP编程

    千次阅读 2021-09-25 13:20:36
    而在19年开始我尝试着在ROS1中使用OOP的形式编程。但是我们知道ROS2和ROS1存在着差异性,所以我们不能直接套用ROS1的编程习惯去实现ROS2的编程。而ROS2是基于DDS开发的去中心化通信,使得ROS2的是实行、可靠性和连续...

    0. 前言

    在使用ROS时候,我们常常感叹ROS的好用,但是在ROS开发方面,从前的我常常会拘泥于教程上的POP的开发方式,这样让我在开发相对大型的机器人程序时就倍感不适。而在19年开始我尝试着在ROS1中使用OOP的形式编程。但是我们知道ROS2和ROS1存在着差异性,所以我们不能直接套用ROS1的编程习惯去实现ROS2的编程。而ROS2是基于DDS开发的去中心化通信,使得ROS2的是实行、可靠性和连续性上都有了增强。这也让ROS2能够适应更庞大的多机器人开发。为此本文针对ROS2去给出一套POP和OOP编程以供各位对比。这里也感谢fishros对ROS2开源社区的贡献。

    在这里插入图片描述

    #include <ros/ros.h>
    #include <std_msgs/UInt8.h>
    
    class TopicPublish
    {
    public:
    
        TopicPublish(std::string pub_name);
        void publish(uint8_t dat);
    
    private:
        
        ros::NodeHandle nh;
    
        ros::Publisher topic_pub;
    };
    
    TopicPublish::TopicPublish(std::string pub_name)
    {
        topic_pub = nh.advertise<std_msgs::UInt8>(pub_name, 10);
    }
    
    void TopicPublish::publish(uint8_t dat)
    {
        std_msgs::UInt8 msgs;
        msgs.data = dat;
        topic_pub.publish(msgs);
    }
    
    int main(int argc, char **argv)
    {
        ros::init(argc, argv, "topic_publish_node");
        TopicPublish mypub("/profect");
        ros::Rate loop(10);
        while(ros::ok())
        {
            mypub.publish(8);
            ros::spinOnce();
            loop.sleep();
        }
    
        return 0;
    }
    

    1.POP和OOP概念

    …详情请参照古月居

    展开全文
  • PHP面向对象OOP编程

    2021-05-19 10:56:46
    PHP面向对象OOP编程 面向对象的概念 面向对象编程(OOP)是我们编程的一项基本技能,PHP5对OOP提供了良好的支持。 如何使用OOP的思想来进行PHP的高级编程,对于提高 PHP编程能力和规划好Web开发构架都是非常有意义的...

    PHP面向对象OOP编程

    • class: 类声明
    • new: 类实例化
    • public: 公开成员,随处可见
    • protected: 受保护成员,仅在当前类或子类中可见
    • private: 私有成员, 仅在当前类可见
    • spl_autoload_register(): 自动加载器
    • extends: 类的扩展
    • abstract 抽象类
    • interface 接口
    • static: 声明类的静态成员
    • $this: 实例引用
    • self: 类的引用
    • trait: 类功能横向扩展

    面向对象的概念

    面向对象编程(OOP)是我们编程的一项基本技能,PHP5对OOP提供了良好的支持。

    如何使用OOP的思想来进行PHP的高级编程,对于提高 PHP编程能力和规划好Web开发构架都是非常有意义的。

    下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法。

    我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的 是一系列的具体功能函数(如果你不使用ODBC接口的话)。

    这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做 任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。

    对象的基本组成

    对象的组成元素:

    是对象的数据模型,用于描述对象的数据,又称为对象的属性,或者对象的成员变量。

    对象的行为::

    是对象的行为模型,用于描述对象能够做什么事情,又被称为对象的成员方法。

    对象特点

    每一个对象都是独一无二的

    对象是一个特定的事物,他的职能是完成特定功能

    对象是可以重复使用

    类的概念

    物以类聚,把具有相似特性的对象对垒到一个类中,类定义了这些相似对象拥有的相同的属性和方法

    类是相似对象的描述,成为类的定义,是该类对象的蓝图或者原型

    类的对象称为一个类的实例(Instance)

    类的属性和方法统称为类成员

    类的实例化

    类的实例化:通过类定义创建一个类的对象

    类的定义属性值都是空或默认值,而对象的属性都有具体的值

    类的定义

    类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写,以中括号开始和结束

    类的实例化为对象时使用关键字new,new之后紧跟类的名称和一对圆括号

    对象中得成员属性和方法可以通过->符号来访问

    OOP面向对象编程

    面向对象编程(Object Oriented Programming,OOP)是一种编程思想,在很多现代编程语言中都有面向对象编程的概念。

    面向对象编程的思想就是把具有相似特性的事物抽象成类,通过对类的属性和方法的定义实现代码共用。将实现某一特定功能的代码部分进行封装,这样可被多处调用,而且封装的粒度越细小被重用的概率越大。

    而面向对象编程的继承性和多态性也提高了代码的重用率。总之,面向对象编程充分地体现了软件编程中的“高内聚,低耦合”的思想。

    PHP 之所以能够成为 Web 开发领域的主流语言,对面向对象开发模式的支持也是重要原因之一。

    面向对象编程的特性

    面向对象编程具有封装、继承、多态三大特性,它们迎合了编程中注重代码重用性、灵活性和可扩展性的需要,奠定了面向对象在编程中的地位。

    1、继承
    继承就是派生类(子类)自动继承一个或多个基类(父类)中的属性与方法,并可以重写或添加新的属性或方法。继承这个特性简化了对象和类的创建,增加了代码的重用性。

    例如,已经定义了 A 类,接下来准备定义 B 类,而 B 类中有很多属性和方法与 A 类相同,那么就可以用 B 类继承 A 类,这样就不用再在 B 类中定义 A 类中已有的属性和方法,从而可以在很大程度上提高程序的开发效率。

    继承分为单继承和多继承,PHP 目前只支持单继承,也就是说一个子类有且只有一个父类。

    2、封装
    封装就是将一个类的使用和实现分开,只保留有限的接口(方法)与外部联系。对于用到该类的开发人员,只要知道这个类该如何使用即可,而不用去关心这个类是如何实现的。这样做可以让开发人员更好地把精力集中起来专注于别的事情,同时也避免了程序之间的相互依赖而带来的不便。

    例如,在使用计算机时,我们并不需要将计算机拆开了解它每个部件的具体用处,只需要按下电源键就能将计算机启动,这就体现了封装的好处。

    3、多态
    对象的状态是多变的。一个对象相对于同一个类的另一个对象来说,它们拥有的属性和方法虽然相同,但却可以有着不同的状态。另外,一个类可以派生出若干个子类,这些子类在保留了父对象的某些属性和方法的同时,也可以定义一些新的方法和属性,甚至于完全改写父类中的某些已有的方法。多态增强了软件的灵活性和重用性。

    PHP class:定义类

    1、变量:实现数据的复用
    2、函数:实现代码块的复用
    3、类:具有相同属性(变量)和方法(函数)的对象集合
    4、对象:复合数据类型,可以储存且有权利对储存在其中的变量进行操作的一组函数
    5、oop:单位是对象,对象是类的实例化的结果 instance
    6、实现类的自动加载 前提必须满足psr-4规范:类文件名称和类同名

    [修饰类的关键字] class 类名{
        类的成员属性和方法;
    }
    

    修饰类的关键字是一个可选参数,可以省略。我们通常使用下面这些关键字来修饰类:

    abstract

    抽象类或方法,被修饰为抽象类之后,类将不能被实例化,但可以被继承。如果类中有至少一个方法被声明为抽象的,那么这个类也必须声明为抽象的。继承一个抽象类的时候,子类必须重新定义父类中的所有抽象方法,而且这些方法的访问控制必须和父类中一样。

    1、抽象方法
    抽象方法是没有方法体的方法,所谓的没有方法体指的就是,在声明方法时候没有花括号{ }以及其中的内容,而是直接在方法名后加上分号结束。另外,在声明抽象方法时要使用“abstract”关键字修饰。格式如下所示:

    abstract 访问权限修饰符 function 方法名1(参数列表);
    abstract 访问权限修饰符 function 方法名2(参数列表);
    
    abstract public function show();
    

    2、抽象类的定义
    只要一个类里面有一个方法是抽象方法,那么这个类就必须定义为抽象类,抽象类也需要使用“abstract”关键字来修饰,抽象类中也可以包含不是抽象方法的成员方法和成员属性,但访问权限不能是私有的(使用 private 关键字修饰),因为抽象类中的方法需要被子类继承。

    1、abstract关键字用于定义抽象类
    2、在抽象方法前面添加abstract关键字可以标明这个方法是抽象方法不需要具体实现{}
    3、抽象类中可以包含普通的方法,有方法的具体实现
    4、继承抽象类的关键字是extends
    5、继承抽象类的子类需要实现抽象类中定义的抽象方法
    6、抽象类不能被实例化,当子类继承抽象类的时候,所有的抽象的方法都必须定义

    <?php
    
    // 抽象类:可以为子类定义一些公共接口作为子类重写的模板来使用
    // 抽象类可以有抽象方法,也可以有具体的方法 抽象类自身时不能被实例化的,需要被继承的子类来实例化对象
    abstract class Person{
        public $name;
        protected $country;
        // 构造方法
        function __construct($name="admin",$country="China"){
            $this->name = $name;
            $this->country = $country;
        }
        // 抽象方法 没有方法体{}
        abstract public function eat();
        abstract protected function say();
        
        // 普通方法
        public function run(){
            echo "runing ……";
        }
    }
    
    // 通过子类继承来实现抽象类中的抽象方法
    class Chinese extends Person{
        public function say(){
            echo $this->name.'是'.$this->country.'人,说'.$this->country.'话<br>';
        }
        public function eat(){
            echo "{$this->name}{$this->country}人,使用筷子吃饭<br>";
        }
    }
    
    $xiaom = new Chinese('小明','中国');
    $xiaom->say();
    $xiaom->eat();
    
    class American extends Person{
        public function say(){
            echo $this->name.'是'.$this->country.'人,说'.$this->country.'话<br>';
        }
        public function eat(){
            echo "{$this->name}{$this->country}人,使用刀叉吃饭<br>";
        }
    }
    $jkx = new American('杰克逊','美国');
    $jkx->say();
    $jkx->eat();
    

    在这里插入图片描述
    抽象类就像是一个“半成品”的类,在抽象类中包含没有被实现的抽象方法,所以抽象类是不能被实例化的,即创建不了对象,也就不能直接使用它。

    3、抽象类的使用
    可以将抽象类看作是为它的子类定义公共接口,将它的操作(可能是部分也可能是全部)交给子类去实现。就是将抽象类作为子类重载的模板使用的,定义抽象类就相当于定义了一种规范,这种规范要求子类去遵守。

    当子类继承抽象类以后,就必须把抽象类中的抽象方法按照子类自己的需要去实现。子类必须把父类中的抽象方法全部都实现,否则子类中还存在抽象方法,所以还是抽象类,也就不能实例化为对象。

    <?php
    abstract class Website{
        public $name = 'willem<br>';
        public $url = 'http://willem.cn<br>';
        abstract function title($title);
        abstract function output();
        abstract function run();
    }
    
    // 子类继承抽象类,来重写抽象方法
    class SonDemo extends Website{
            
        public function title($title){
            echo $title;
        }
        public function output(){
            echo $this -> name.$this -> url;
        }
        
        // 实在用不到的可以将其函数体留空,但必须要把抽象方法全部都实现
        public function run(){
            
        }
    }
    
    $obj = new SonDemo();
    $obj -> title("抽象类和抽象方法");
    $obj -> output();
    

    在这里插入图片描述

    final:

    使用 final 修饰的类不能被继承,而使用 final 修饰的方法不能在子类中重新定义。

    注意:

    一个类可以包含有属于自己的常量、变量(在类中称为“成员属性”或者“属性”)以及函数(在类中称为“成员方法”或者“方法”)。

    self:: 的限制

    使用 self:: 或者 CLASS 对当前类的静态引用,取决于定义当前方法所在的类:

    <?php
    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
    ?>
    

    举个栗子 (单例对象)

    class Father {
        protected static $_instance = null;
        
        static public function getInstance()
        {
            if(self::$_instance === null)
            {
                //获取类的实例 self 始终永远和当前类进行绑定
                //1. self 始终永远和当前类进行绑定
                //2. self 在静态继承上下文中, 不能动态的识别或者设置静态成员的调用者
                self::$_instance = new self();
            }
    
            return self::$_instance;
        }
    }
    
    
    class son1 extends Father 
    {
        protected static $_instance = null;
    }
    
    class son2 extends Father
    {
        protected static $_instance = null;
    }
    
    var_dump(Father::getInstance());
    var_dump(Son1::getInstance());
    var_dump(Son2::getInstance());
    /* 
    object(Father)#1 (0) { } 
    object(Father)#1 (0) { } 
    object(Father)#1 (0) { } 
    */
    
    //使用self 实例化得到的都是Father类的同一个对象  (单例继承)
    
    

    成员属性访问权限

    说明public(默认)privateprotected
    同一个类中访问
    在子类中访问×
    在类的外部访问××

    static:静态成员,无需实例化对象,即可通过类名访问。

    $this当前对象

    在 PHP 面向对象编程中,对象一旦被创建,在对象中的每个成员方法里面都会存在一个特殊的对象引用“this ” 。 成员方法属于哪个对象 , “ this”。成员方法属于哪个对象,“this”。

    成员方法属于哪个对象,“this”就代表哪个对象,与连接符->联合使用,专门用来完成对象内部成员之间的访问。

    1、parent关键字可以用于调用父类中被子类重写了的方法

    2、self关键字可以用于访问类自身的成员方法,静态成员和类常量;不能用于访问类自身的属性,使用常量的时候不需要在常量 const 名称前面添加 $ 符号。

    3、static::关键字用于访问类自身定义的静态成员,访问静态属性时需要在属性前面添加$符号。

    4、常量属性const不能使用对象访问,仅能使用类访问,在类本体内可以使用“self::常量名”,在类本体外可以使用“类名::常量名”。

    示例1

    <?php
    class Person{
        public $name = 'shanghai';
        public $age = 20;
        protected static $tel;
    
        public function __construct($name,$age,$tel){
            $this->name = $name;
             $this->age = $age;
             self::$tel = $tel;
            echo "姓名:{$this->name},年龄:{$this->age},电话:". self::$tel;
        }
    
        public static function _setTel($_tel){
            self::$tel = $_tel;
            echo static::_getTel();
        }
        public static function _getTel(){
            return  self::$tel;
        }
    }
    
    class Son extends Person{
        private $sex;
        public static $email = "2602138376@qq.com";
        public function __construct($name,$age,$tel,$sex){
            $this->sex = $sex;
            parent::__construct($name,$age,$tel);
            echo ",性别:{$this->sex}";
        }
    
        public function getSex(){
            return $this->sex;
        }
    
        public static function _getTel(){
            echo "电话:".parent::_getTel();
            echo "邮箱:".self::$email;
        }
    }
    
    
    
    $p1 = new Person("shang",20,18949064166);
    echo "<hr>";
    
    echo $p1->name.'——'.$p1->age.'——';
    echo Person::_getTel().'——';
    Person::_setTel("15056825056");
    
    echo "<hr>";
    
    $s1 = new Son("孙小果",18,13096578824,"女");
    echo "<hr>";
    
    echo $s1->name.'——'.$s1->age;
    echo "<hr>";
    
    echo Son::_getTel();
    echo "<hr>";
    
    echo $s1->getSex();
    Son::$email = "admin@php.cn";
    echo Son::_getTel();
    

    在这里插入图片描述

    声明成员属性修饰关键字

    在类中声明成员属性时,变量前面一定要使用一个关键字来修饰,例如 public、private,static 等,但这些关键字修饰的变量都具有一定的意义。

    如果不需要有特定意义的修饰,可以使用“var”关键字,一旦成员属性有其他的关键字修饰就需要去掉“var”。

    【示例】创建一个 Students 类并在类中声明一些成员属性,代码如下所示:

    <?php
    class Students{
    	// 成员属性 一定要有访问修饰符 public protected private static
        public $name = 'zhang';
        public $age = 18;
        private $sex; // 抽象属性 null
        protected static $school;
    }
    ?>
    

    提示:

    权限修饰符可以和定义静态变量的关键字 static 混合在一起使用,如上面代码中所示。

    类中定义成员方法

    在类中定义的函数被称为成员方法。函数和成员方法唯一的区别就是,函数实现的是某个独立的功能,而成员方法是实现类中的一个行为,是类的一部分。

    可以在类中声明多个成员方法,成员方法的声明和函数的声明完全一样,只不过在声明成员方法时可以在function关键字的前面加一些访问权限修饰符来控制访问权限,例如 public、private、protected 等。

    【示例】在上面示例中创建的 Students 类中创建一些成员方法。

    <?php
    class Students{
    	// 成员属性 一定要有访问修饰符 public protected private static
        public $name = 'zhang';
        public $age = 18;
        private $sex; // 抽象属性 null
        protected static $school;
    	
    	// 成员实例方法
        public function Write(){
           echo '正在写字中……';
        }
        protected static function Read(){
    		echo '正在读书中……';
        }
        function Listen(){
            echo '正在听力中……';
        }
    }
    ?>
    

    成员方法前面的权限修饰符可以省略,省略后默认权限为 public。

    在类中成员属性和成员方法的声明都是可选的,可以同时存在,也可以单独存在,具体可以根据实际情况而定。

    在 PHP7 中,引入了类型声明,我们可以为成员方法的形参和返回值声明类型,格式如下所示:

    [权限修饰符] function 方法名 (类型 参数1, 类型 参数2, ..., 类型 参数n) : 返回值类型 {
        ... ...
    }
    

    PHP7 中支持声明的参数类型包括整型、浮点型、字符串型和布尔类型。

    示例代码如下所示:

    <?php
    class Students{
        var $name;
        public $age;
        private $sex;
        public static $school;
        public function Write(string $a, int $b):bool{
           
        }
        protected static function Read(string $str):int{
    
        }
        function Listen(int $num):bool{
    
        }
    }
    ?>
    

    PHP new:实例化对象

    将类实例化成对象非常容易,只需要使用 new 关键字并在后面加上一个和类名同名的方法即可。

    当然如果在实例化对象时不需要为对象传递参数,在 new 关键字后面直接用类名称即可,不需要再加上括号。

    对象的实例化格式如下:

    变量名 = new 类名(参数数列表); 或 变量名 = new 类名;
    

    参数说明如下:

    变量名:

    通过类所创建的一个对象的引用名称,可以通过这个名称来访问对象的成员;

    new:关键字,表明要创建一个新的对象;

    类名:表示新对象的类型;

    参数列表:

    指定类的构造方法用于初始化对象的值,如果类中没存定义构造函数,PHP - 会自动创建一个不带参数的默认构造函数。

    【示例】创建一个类并将其实例化。

    <?php
    class Students
    {
    
    }
    $person1 = new Students();
    $person2 = new Students;
    $person3 = new Students;
    var_dump($person1);
    echo '<br>';
    var_dump($person2);
    echo '<br>';
    var_dump($person3);
    ?>
    
    

    一个类可以实例化出多个对象,每个对象都是独立的。在上面的代码中通过 Students 类实例化出三个对象 person1 、 person1、person1、person2 和 $person3,相当于在内存中开辟了三份空间用于存放每个对象。

    使用同一个类声明的多个对象之间是没有联系的,只能说明他们都是同一个类型,每个对象内部都有类中声明的成员属性和成员方法。就像独立的三个人,都有自己的姓名,性别和年龄的属性,每个人都有说话、吃饭和走路的方法。

    对象的访问

    对象中包含成员属性和成员方法,访问对象中的成员和访问数组中的元素类似,只能通过对象的引用来访问对象中的成员。

    但还要使用一个特殊的运算符号->来完成对象成员的访问,访问对象中成员的语法格式如下所示:

    变量名 =  new 类名(参数);   //实例化一个类
    变量名 -> 成员属性 = 值;    //为成员属性赋值
    变量名 -> 成员属性;        //直接获取成员属性的值
    变量名 -> 成员方法();      //访问对象中的成员方法
    

    下面通过一个示例来演示一下:

    <?php
        class Website{
            public $name, $url, $title;
            public function demo(){
                echo '成员方法 demo';
            }
        }
    
        $student = new Website();
        $student -> name = 'php中文网';
        $student -> url = 'http://php.cn';
        $student -> title = '实例化对象';
        echo $student -> name.'<br>';
        echo $student -> url.'<br>';
        echo $student -> title.'<br>';
        $student -> demo();
    ?>
    
    

    魔术方法

    魔术方法作用
    __construct()实例化类时自动调用(构造函数)
    __destruct()类对象使用结束时自动调用(析构函数)
    __set()在给未定义的属性赋值时自动调用
    __get()调用未定义的属性时自动调用
    __isset()使用 isset() 或 empty() 函数时自动调用
    __unset()使用 unset() 时自动调用
    __sleep()使用 serialize 序列化时自动调用
    __wakeup()使用 unserialize 反序列化时自动调用
    __call()调用一个不存在的方法时自动调用
    __callStatic()调用一个不存在的静态方法时自动调用
    __toString()把对象转换成字符串时自动调用
    __invoke()当尝试把对象当方法调用时自动调用
    __set_state()当使用 var_export() 函数时自动调用,接受一个数组参数
    __clone()当使用 clone 复制一个对象时自动调用(克隆)
    __debugInfo()使用 var_dump() 打印对象信息时自动调用

    属性重载(属性拦截器)

    PHP所提供的 重载(overloading)是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。

    当调用当前环境下不可访问(未定义或不可见)的类属性或方法时,重载方法会被调用。

    ● 属性的重载 __get 与__set
    ● 方法的重载 __call 与 __callStatic

    <?php  
    // PHP 重载
    class Credit{
        private $idNum;
        private $age;
        
        // 魔术方法 构造函数 如果我没有显示的定义__construct方法时候,系统在实例化对象的时候会自动初始一个无参的构造函数
        public function __construct($idNum,$age){
            $this->idNum = $idNum;
            $this->age = $age;
        }
    
        // 我们也可以显示的声明重载方法 __get __set
        public function __set($name,$value){
            echo "Setting $name to $value<br>";
            $this->$name = $value;
            return $this->$name;
        }
        public function __get($name){
            return $this->$name;
        }
    }
    
    $c = new Credit('341226186915868525',88);
    # 访问未定义的成员属性时,重载方法会被调用
    $c->name = 'zhang'; // __set
    echo $c->name; // __get
    # 访问私有成员属性
    echo "<br>";
    $c->idNum = "****************";
    echo $c->idNum;
    

    在这里插入图片描述

    导出问题:因为魔术方法都是公有的,所以一些私有成员的不可见性就不会生效。

    解决这一问题,我们需要用到属性重载处理(属性拦截器)

    __set()当给不可访问的属性赋值的时候会触发

    • 有两个参数第一个参数是成员名第二个参数是成员的值

    __get()当读取不可访问的属性的时候会触发

    • 有一个参数是成员名

    其中不可访问成员指的是:没有定义的成员,还有因为受到访问控制而访问不到的

    <?php  
    // PHP 重载
    class Credit{
        private $idNum;
        private $age;
        
        public function __construct($idNum,$age){
            $this->idNum = $idNum;
            $this->age = $age;
        }
    
        // 设置 中转站
        public function __set($name,$value){
            // 根据属性名称$name 生成对应的属性访问私有接口
            // 'set'.'IdNum' = setIdNum
            $method = 'set'.ucfirst($name);
            // method_exists() 检测对象中是否存在某个方法
            return method_exists($this,$method)?$this->$method($name,$value):null;
        }
        private function setIdNum($name,$value){
            // property_exists()检测对象中是否存在某个属性
            if(property_exists($this,$name)){
                return $this->$name = strlen($value)==18?$value:null;
            }
        }
        private function setAge($name,$value){
            if(property_exists($this,$name) && intval($value)>0){
                return $this->$name = $value;
            }else{
                return $this->$name = null;
            }
        }
        
        // 访问 中转站
        public function __get($name){
            $method = 'get'.ucfirst($name);
             return method_exists($this,$method)?$this->$method($name):null;
        }
        private function getIdNum($name){
            // 用户修改并查看的属性是否存在,并且属性内容已修改成功,不为空。
            if(property_exists($this,$name) && !empty($this->$name)){
                return substr_replace($this->$name,"****",-4,4);
            }else{
                return "身份证信息不合法";
            }
        }
        private function getAge($name){
            if(property_exists($this,$name) && !empty($this->$name)){
                if($this->$name<18){
                    return "年龄小于18岁";
                }elseif($this->$name<35){
                    return "年龄小于35岁";
                }else{
                    return "年龄大于35岁";
                }
            }else{
                    return "年龄不合法";
            }
        }
    }
    
    $c = new Credit('341226186915868525',88);
    $c->idNum = "341226186915868585";
    echo $c->idNum."<br>";
    $c->age = 25;
    echo $c->age;
    

    在这里插入图片描述
    拦截器典型的作用:

    1、给出友好提示

    2、执行默认操作

    方法重载(方法拦截器)

    当调用不可访问的方法时,__call会被自动调用, 还会自动传给__call两个参数:分别代表被调用的不存在的方法名 和调用时传递的参数

    __callStatic()与 __call类似,当静态调用一个不可访问的方法时,会自动执行!

    <?php  
    # 方法拦截器,当从类的外部,访问类中不存在或无权限访问的方法的时候,会自动调用它
    class  User{
        public static function normal(){
            return __METHOD__;
        }
        # 方法拦截器 魔术方法 __call(不存在的方法名, 调用时传递的参数数组)
        public function __call(string $method,array $args){
            printf("调用对象方法%s(),参数为:[%s]<br>",$method,implode(",",$args));
        }
        # 静态方法拦截器: __callSatic(方法名称, 参数数组)
        public static function __callStatic(string $method,array $args){
            printf("调用静态方法%s(),参数为:[%s]<br>",$method,implode(",",$args));
        }
    }
    
    (new User)->getInfo('刘亦菲','美女','170cm');
    User::getName("小爱","咩咩",'皮特朱');
    echo User::normal();
    

    在这里插入图片描述

    事件委托(方法重定向)

    访问类中不存在的成员方法时,会被魔术方法拦截,把请求重定向到别的类的成员方法来处理。

    <?php
    # 被委托的类
    class Base
    {
        public function write(...$args) //...为展开
        {
            printf('方法名: %s(), 参数 [%s]',__METHOD__, implode(', ', $args));
        }
        public static function fetch(...$args)
        {
            printf('方法名: %s(), 参数 [%s]',__METHOD__, implode(', ', $args));
        }
    }
    
    # 工作类
    class Work
    {
        # 事件委托时,重定向到的目标类
        private $base;
        
        # 将$base初始化
        public function __construct(Base $base)
        {
            $this->base = $base;
        }
        
        # 方法拦截器,将$this->write()重定向到$this->base->write()
        public function __call($name, $args)
        {
            # 将$this->$name()重定向到$this->base->$name()
            if (method_exists($this->base, $name))
            # return $this->base->$name($name, $args); 这个也可以,但基本上不用
            # 用回调的方式来调用: call_user_func_array(函数, 参数数组)
            # 如果是一个对象的方法,应该使用数组的方式: [对象, '方法名']
            return call_user_func_array([$this->base, 'write'], $args);
        }
        
        # 方法拦截器,将self::fetch()重定向到Base::fetch()
        public static function __callStatic($name, $args)
        {
            # 将self::$name()重定向到Base::$name()
            if (method_exists('Base', $name))
            return call_user_func_array(['Base', 'fetch'], $args);
        }
    }
    
    // 客户端代码
    // $base = new Base();
    // $work = new Work($base);
    $work = new Work(new Base);
    $work->write(11,22,33);
    echo "<br>";
    $work::fetch('皮特朱', '咩咩', '欧阳');
    

    在这里插入图片描述

    实战案例(查询构造器)

    事件委托/方法拦截器
    实战: 数据库查询构造器(链式查询)

    <?php
    # 查询类
    class Query
    {
        // 连接对象
        protected $db;
        // 数据表
        protected $table;
        // 字段列表
        protected $field;
        // 记录数量
        protected $limit;
        // 添加数据
        protected $values;
        // 操作条件
        protected $where;
        
        # 构造方法: 连接数据库
        public function __construct($dsn, $username, $password) 
        {
            $this->connect($dsn, $username, $password);
        }
        // 连接数据库
        private function connect($dsn, $username, $password)
        {
            $this->db = new PDO($dsn, $username, $password);
        }
    
    
        # 设置默认的数据表名称
        public function table($table)
        {
            $this->table = $table;
            return $this;
        }
        # 设置默认的字段名称
        public function field($field)
        {
            $this->field = $field;
            return $this;
        }
        // 链式方法: 设置查询数量
        public function limit($limit)
        {
            $this->limit =empty($limit)?"":"LIMIT $limit";
            return $this;
        }
        // 设置修改或添加的数据
        public function values($values)
        {
            $this->values = $values;
            return $this;
        }
        // 设置where条件
        public function where($where)
        {
            $str = '';
            if (!empty($where)) {
                foreach ($where as $key => $value) {
                    if(is_array($where)){
                        if(count($where)>1){
                            $str .= $key.'='.$value.' and ';
                        }else{
                            $str .= $key.'='.$value;
                        }
                    }
                }
            }
            $str = count($where)>1?substr($str,0,-4):$str;
            $this->where = empty($where)?"":"where $str";
            return $this;
        }
    
        // 生成SQL语句
        protected function getSql($key)
        {
            switch ($key) {
                case 'select':
                    return sprintf('SELECT %s FROM %s %s %s', $this->field, $this->table, $this->where, $this->limit);
                    break;
                case 'update':
                    return sprintf('UPDATE %s SET %s = %s %s', $this->table, $this->field, $this->values,$this->where);
                    break;
                case 'insert':
                    $this->field = $this->field == "*"?"":$this->field;
                    return sprintf('INSERT INTO %s (%s) VALUES (%s)', $this->table, $this->field, $this->values);
                    break;
                case 'delete':
                    return sprintf('DELETE FROM %s %s', $this->table, $this->where);
                    break;
            }
        }
    
        // 执行SQL语句
        public function select()
        {
            return $this->db->query($this->getSql('select'))->fetchAll(PDO::FETCH_ASSOC);
        }
        public function insert()
        {
            return $this->db->query($this->getSql('insert'));
        }
        public function update()
        {
            return $this->db->query($this->getSql('update'));
        }
        public function delete()
        {
            return $this->db->query($this->getSql('delete'));
        }
    }
    
    # 数据操作类
    class DB
    {
        // 静态方法委托
        public static function __callStatic($name, $args)
        {
            // 获取到查询类的对象: new Query()
            $dsn = 'mysql:host=172.20.31.97;dbname=hht';
            $username = 'hht';
            $password = 'rGRCAeDPfJaa63rs';
            $query = new Query($dsn, $username, $password);
            // 直接跳到Query类中的具体方法来调用
            return call_user_func_array([$query, $name], $args);
        }
    }
    # 查询记录
    $result = DB::table('users')->field("*")->select();
    echo "<pre>";
    print_r($result);
    
    # 添加记录
    $result = DB::table('blogs')->field('*')->values("'2','2','php重定向','事件委托/方法拦截器 实战: 数据库查询构造器(链式查询)', '2021-05-10 15:58:26'")->insert();
     echo "<pre>";
    print_r($result);
    
    $result = DB::table('blogs')->field("*")->limit(5)->select();
    echo "<pre>";
    print_r($result);
    
    # 修改记录
    DB::table('blogs')->field('title')->values('"我的标题被修改了"')->where(["id"=>1])->update();
    
    $result = DB::table('blogs')->field("*")->limit(1)->select();
    echo "<pre>";
    print_r($result);
    
    # 删除记录
    DB::table('blogs')->where(["user_id"=>"2"])->delete();
    
    $result = DB::table('blogs')->field("*")->select();
    echo "<pre>";
    print_r($result);
    
    

    在这里插入图片描述
    数据库表SQL脚本文件

    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for blogs
    -- ----------------------------
    DROP TABLE IF EXISTS `blogs`;
    CREATE TABLE `blogs` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `user_id` int(11) NOT NULL,
      `title` varchar(128) NOT NULL,
      `content` text,
      `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`),
      KEY `user_id` (`user_id`),
      CONSTRAINT `blogs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of blogs
    -- ----------------------------
    INSERT INTO `blogs` VALUES ('1', '1', '可用的路由方法', '路由器允许你注册能响应任何', '2020-09-26 16:43:00');
    INSERT INTO `blogs` VALUES ('3', '1', '基本路由', '构建基本路由只需要一个 URI 与一个 闭包', '2020-09-26 16:42:03');
    INSERT INTO `blogs` VALUES ('4', '2', 'web前端开发', 'HTML、css、js', '2020-09-30 22:34:46');
    INSERT INTO `blogs` VALUES ('5', '1', '重定向路由', '如果要定义重定向到另一个 URI 的路由', '2020-09-26 17:09:49');
    
    -- ----------------------------
    -- Table structure for users
    -- ----------------------------
    DROP TABLE IF EXISTS `users`;
    CREATE TABLE `users` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `account` varchar(20) NOT NULL,
      `password` varchar(32) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of users
    -- ----------------------------
    INSERT INTO `users` VALUES ('1', 'admin', '1234');
    INSERT INTO `users` VALUES ('2', 'user1', '0000');
    
    

    trait: 类功能横向扩展

    在PHP中代码只能单继承,为了实现类代码的复用因此实现了trait,trait类与普通class不同它自身无法实例化,只能通过use在class中引用trait,然后这个类就能使用trait中的方法。

    共用的一些属性和方法提取出来做公共trait类,就像是装配汽车的配件,如果你的类中要用到这些配件,就直接用use导入就可以了,相当于把trait中的代码复制到当前类中。

    因为trait不是类,所以不能有静态成员,类常量,当然也不可能被实例化。

    如果说:继承可以纵向扩展一个类,那么trait就是横向扩展一个类功能。

    在这里插入图片描述
    通俗点讲:trait就是为了代码复用而生
    例一:创建两个trait类,并使用。(trait类不仅可以定义方法,也可以定义属性)

    <?php  
    trait test1{
    	public $name = "zhang";
    	public function aa(){
    		return "test1";
    	}
    }
    
    trait test2{
    	public function bb(){
    		return "test2";
    	}
    }
    
    class test3{
        //引入关键字 use 
    	use test1,test2;
    	public function getName($name){
    		return "My name is  $name";
    	}
    }
    
    $obj = new test3;
    echo $obj->aa()."<br>";
    echo $obj->bb()."<br>";
    echo $obj->getName($obj->name)."<br>";
    /*
    test1
    test2
    My name is zhang
     */
    
    

    构造函数__construct()

    __construct():构造函数/方法(构造器)

    1、对公共属性进行初始化赋值
    2、记录当前类被实例化的次数

    构造函数(constructor method,也称为构造器)是类中的一种特殊函数,当使用 new 关键字实例化一个对象时,构造函数将会自动调用。

    构造函数就是当对象被创建时,类中被自动调用的第一个函数,并且一个类中只能存在一个构造函数。

    和普通函数类似构造函数也可以带有参数,如果构造函数有参数的话,那么在实例化也需要传入对应的参数,例如new Students($name, $age),否则会报错。

    PHP 类的自动加载机制

    在使用面向对象模式开发程序时,通常大家习惯为每个类都创建一个单独的文件。

    这样会很容易实现对类进行复用,同时将来维护时也很便利,这也是面向对象程序设计的基本思想之一。

    当需要使用一个类时,只需要直接使用 include 或 require 将其包含进来即可,然后通过客户端代码加载这个类,然后进行实例化等一系列后续操作。

    注意:类文件的名称需要与类名相同,另外一个类文件中只能定义一个类

    新建 Player.php

    <?php
    class Player{
    	# 成员属性 一定要有访问修饰符 public protected private static
    	public $name = 'willem';
    	public $height;
    	public $team;
        # 受保护成员,仅限本类及子类中访问
    	protected $playerNum;
        # 私有成员,仅限本类中使用
        # 如何给私有成员赋值 1.可以通过构造函数 2.可以通过魔术方法
    	private $weight;
    
    	# 成员实例方法
    	public function jog(){
    		echo "{$this->name} is chen";
    	}
    
    	# 魔术方法名称: 由系统调用
    	# __set __get __call __callStatic __construct
    	
    	public function __construct($name,$height,$team){
    		// 对对象的公共属性进行初始化赋值
    		// 记录当前类被实例化的次数
    		$this->name = $name;
    		$this->height = $height;
    		$this->team = $team;
    	}
    }
    ?>
    
    

    新建 Product.php

    <?php
    class Product{
    	public $name;
    	public $price;
    	
    	public function __construct($name,$price){
            $this->name = $name;
            $this->price = $price;
        }
    
    	public function show(){
            return "{$this->name},¥{$this->price}";
        }
    }
    ?>
    
    

    新建 autoload.php

    spl_autoload_register() 自动加载函数

    <?php
    // 注册类的自动加载器
    spl_autoload_register(function ($class){
        // 加载当前文件夹下的类
        $file = './'.$class.'.php';
        require $file;
    });
    
    $james = new Player('james','198cm','Laker');
    echo $james->name."<br>";
    echo $james->team."<br>";
    echo $james->jog()."<br>";
    $mobile = new Product("Redmi note9 pro",1599);
    echo $mobile->show();
    

    在这里插入图片描述

    PHP instanceof:判断对象是否属于某个类

    <?php
     spl_autoload_register(function ($class){
           require './'.$class.'.php';
        });
    
    	$good = new Goods('被子',266,8);
    	$james = new Player('james','198cm','Laker');
    
    //  instanceof 运算符,可以判断一个对象是否属于某一个类
    echo "<pre>";
    var_dump($good);
    var_dump($james);
    /*
    object(Goods)#2 (3) {
      ["num":"Goods":private]=>
      int(8)
      ["name"]=>
      string(6) "被子"
      ["price"]=>
      int(266)
    }
    object(Player)#3 (5) {
      ["name"]=>
      string(5) "james"
      ["height"]=>
      string(5) "198cm"
      ["team"]=>
      string(5) "Laker"
      ["playerNum":protected]=>
      NULL
      ["weight":"Player":private]=>
      NULL
    }
     */
    
    var_export($good instanceof Goods); // true
    var_export($james instanceof Goods); // false
    var_export($james instanceof Player); // true
    	
    ?>
    

    PHP interface:接口

    继承的特性简化了对象、类的创建,增加了代码的重用性。

    但 PHP 只支持单继承,也就是说每个类只能继承一个父类。为了解决这个问题,PHP 引入了接口。

    接口是一种特殊的抽象类,而抽象类又是一种特殊的类,所以可以将接口看作是一种特殊的类。

    接口就是把不同类的共同行为进行定义,然后在不同的类里面实现不同的功能。

    1、interface定义接口,implements用于表示类实现某个接口
    2、接口里面的方法没有具体的实现,无需写**{}**
    3、实现了某个接口的类必须提供接口中定义的方法的具体实现
    4、不能实例化接口,但是能够判断某个对象是否实现了某个接口。
    5、instanceof关键字判断某个对象是否实现了某个接口 $object instanceof interface
    6、接口可以继承接口(interface extends interface)
    7、接口中定义的所有方法都必须是公有,这是接口的特性

    1、接口的声明
    如果抽象类中的所有方法都是抽象方法,我们就可以使用另外一种声明方式——“接口”技术。

    我们都知道类的声明是使用“class”关键字,而接口的声明则是使用“interface”关键字。

    声明接口的格式如下所示:

    interface 接口名称{
      // 常量成员
      // 抽象方法
    }
    

    接口中所有的方法都是抽象方法,而且不需要在方法前使用 abstract 关键字进行修饰。

    而且在接口中也不需要显示地使用 public 访问权限来进行修饰,因为默认权限就是 public 的,也只能是 public(公有的)。

    另外,接口中不能声明变量,只能使用 const 关键字声明为常量类型的成员属性。

    接口和抽象类一样也不能实例化为对象,它是一种更严格的规范,也需要通过子类来实现。与抽象类不同的是,接口可以直接使用接口名称在接口外面获取常量成员的值。

    <?php
    interface Demo{
        const NAME = 'wgchen';
        const URL = 'http://wgchen.cn';
        function fun1();
        function fun2();
    }
    echo Demo::NAME.'<br>';
    echo Demo::URL.'<br>';
    

    在这里插入图片描述

    2、接口的应用
    因为接口不能进行实例化操作,所以要使用接口中的成员,就必须借助子类。在子类中继承接口需要使用 implements 关键字,如果要实现多个接口的继承,那么每个接口之间使用逗号,分隔。

    在使用 implements 关键字继承接口的同时,还可以使用 extends 关键字来继承一个类。也就是说,可以在继承一个类的同时实现多个接口,但一定要先使用 extends 继承类再去使用 implements 实现多个接口。语法格式如下:

    class 子类名 extends 父类名 implements 接口 1, 接口 2, ..., 接口 n {
      // 实现所有接口中的抽象方法
    }
    

    举个栗子:

    <?php  
    interface Demo{
        const NAME = 'wg';
        const URL = 'http://gw.cn';
        static function getName();
        static function getUrl();
    }
    
    class Website implements Demo{
        static public function getName(){
            echo self::NAME.'<br>';
        }
        static public function getUrl(){
            echo self::URL;
        }
    }
    // 通过接口可以直接访问常量
    echo Demo::NAME."<br>";
    echo Demo::URL."<br>";
    // 调用Website类实现的静态方法
    Website::getName();
    Website::getUrl();
    

    在这里插入图片描述

    提示:既然要通过子类继承了接口中的方法,那么接口中的所有方法都必须在子类中实现,否则 PHP 将抛出如下所示的错误信息:

    说了这么多,那么使用接口具体有什么作用呢?

    其实它的作用很简单,当有很多人一起开发一个项目时,每个人都可能会去调用别人写的一些类。这时有人就会问了,我怎么知道别人的某个功能的实现方法是怎么命名的呢?

    这个时候 PHP 接口就起到作用了。

    简单来说,我们可以将接口看作一个类的模板或者类的规定。

    如果你属于这类,你就必须遵循这个类的规定,少一个都不行,但是具体怎么去做,那是你的事。也就是说我们可以定义一些接口,每个接口中都包含若干的抽象方法。

    在多人开发时,每个人都根据自己的需要来实现一部分接口,这样就可以避免我们在调用别人开发的方法时不知道方法名的尴尬了。

    展开全文
  • 5图理解OOP编程的多态

    2021-04-24 21:47:15
    而多态性指的是对象的多态性,不是指类。所以需要我们new一个对象,由这个对象可实现多态。前提是这个new出来对象的类,需要继承类或者implements接口,也就是必须有父类。以下均使用Java语言举例说明。...
  • python中的OOP编程

    2020-12-24 10:11:58
    你完全错了.也许这是一本可怕的书,其作者犯了严重错误.的确,使用其他代码的代码应该避免重大的反驳,坚持...哎呀,即使是实现的作者,在处理其他代码(例如其他模块)时,也可以/应该仍然可以对接口进行编程.同样,即使您...
  • 图书信息内容简介《冒号课堂:编程范式与OOP思想》是以编程范式和抽象机制为主线阐述编程设计思想的图书。冒号课堂编程范式与oop思想它以编程语言为形、以编程范式为神、以抽象机制为本,采用课堂对话的形式讲述编程...
  • 在 Java OOP 编程中的注意事项 重写 方法 字段 反射 static 接口 abstract Maven JUnit 重写 方法 当子类重写超类的方法时,子类该方法的被访问权限不能低于超类方法。如果超类方法为 public,则子类被重写的方法也...
  • classdef CRing% CRING: class for construct some object of Ring% and show they in the figure% Syntax for generate and use the object of class CRing:% ringObj = CRing(innerRadius,outerRadius...
  • 1 面向对象编程简介2 类和实例3 ...面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。 面向过程的程序设计把计算机程.
  • java面向对象编程oop) 面向对象编程:是一种以对象为原子性的编程思想,每个对象之间相互联系构建了整个系统、 面向对象的本质就是以类组织代码,以对象封装数据。 面向过程编程:是一种注重编程过程的思想,他...
  • (已push至github)贪吃蛇AI——Python OOP编程练习README写的比较清楚啦代码在GithubGithub 链接记得点个star哦!!!谢谢老板 README写的比较清楚啦 代码在Github Github 链接 ...记得点个star哦!...
  • 类型的访问修饰符允许开发人员对类成员的访问进行限制,这是PHP5的新特性private protected public同一个类中 √ √ √类的子类中 √ √所有的外部成员 √public;echo $this->protected;echo $this->...
  • python作为一种解释性语言,其主要的编程方式就是面向对象,而且python的框架django也是主要面向对象的编程。类(class)和对象(object)类(class)是用来描述具有相同属性(attribute)和方法(method)对象的集合。对象...
  • 互联网技术飞跃发展的背后,是无数工程师们利用编程...JavaOOP面试题1、什么是B/S架构?什么是C/S架构2、Java都有哪些开发平台?3、什么是JDK?什么是JRE?4、Java语言有哪些特点5、面向对象和面向过程的区别6、什么...
  • OOP的六大原则

    2021-01-16 21:47:02
    面向对象编程的三大特性:封装、继承、多态。具有这样特性的oop语言,在进行项目显实现是就容易达到重用性、灵活性和扩展性。 开闭原则(Open Close Principle) 对扩展开放、对修改关闭。这是让我们的系统达到一个...
  • javaoop考试题

    2021-02-28 07:10:44
    1.编写一个类Student,代表学员,要求如下,(5分)·具有属性:姓名,年龄,其中年龄不能小于16岁,否则输出错误信息。·具有方法:自我介绍,负责输出该学员的姓名和年龄编写测试类Student1Test进行测试,看是否符合...
  • 共回答了16个问题采纳率:87.5%Deep understanding of Java Object Oriented Programming. Able to use encapsulation, inheritance, polymorphism, abstraction. Able to use generic class and macro definition ...
  • 8、什么是OOP?9、类与对象的关系?10、Java中有几种数据类型11、标识符的命名规则。12、instanceof关键字的作用13、什么是隐式转换,什么是显式转换14、Char类型能不能转成int类型?能不能转化成string类型,能不能转...
  • php面向对象编程(英语:Object-oriented programming,缩写:OOP),对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。个人理解,万物皆对象,通过定义类然后为这个类添加属性方法,再将其...
  • 如果你尚未用OOP思想来完善你的程序设计,那你真的OUT了。 PHP中的面向对象,是从PHP5开始完善的,之前的版本本质上还是面向过程的。面向过程只为我们程序提供了一定程度的代码重用。然而,没有OO的特质,依然不妨碍...
  • 本文概述面向对象编程是围绕对象而不是动作和数据而不是逻辑组织的编程模型。类类是一个实体, 它确定对象的行为方式以及对象将包含的内容。换句话说, 构建特定类型的对象是一个蓝图或一组指令。在PHP中, 使用class...
  • Java基础之面向对象编程(OOP) 初步认识面向对象 面向对象思想: 物以类聚,分类的思想模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后才对某个分类下的细节进行面向过程的思考。 ...
  • 面向对象的编程oop)初识面向对象面向对象&面向过程什么是面向对象方法回顾和加深对象的创建分析类与对象的关系创建与初始化对象面向对象三大特征(重点)封装继承多态Static 关键字抽象类和接口抽象类接口 ...
  • 面向对象编程 OOP

    2021-07-12 22:26:46
    OOP:Object Oriented Programming,面向对象编程。了解面向对象编程之前,需要了解下面向过程编程。现在有一个实际问题需要编程解决,把大象装冰箱里分几步?如果用面向过程的语言去实现则思路如下: void main()...
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼现在,需要升级ACCP教员类,增加一种新类型:ACCPDBTeacher,该类型的教员专门负责教授数据库,具有属性“姓名”、“所属中心”;具有方法“授课”(授课步骤依次是:打开...
  • 面向对象编程OOP)和函数式编程(FP) 编程的本质万变不离其宗就是,操纵一坨数据。 当然操纵的方式有许多,存储的方式也五花八门,但是本质不变,就是访问数据(读取以及改变)。 词条:操作数据 ​ 面向对象:...
  • OOP面对对象编程(Object Oriented Programming)是一种计算机编程架构OOP的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。 基本思想:把组件的实现和接口分开,并且让组件具有多态性...
  • Python面向对象编程面试题有哪些?想在Python面试过程中取得成功,首要做的准备就是熟悉一些Python面试题,把握好方向,让我们更能准确的把握方向。Python面向对象编程面试题有哪些?面向对象编程和函数式编程(面向...
  • 面向对象编程OOP)

    2021-10-11 19:42:04
    面向对象(OOP Object Orient Programming)是java编程的核心思想。 三大特性:封装,继承,多态 主要组成:类;对象;属性;动作(方法) 类:对某一类有相同特征的事物的抽象,或者说具有同种属性和行为的对象...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 89,462
精华内容 35,784
关键字:

oop编程