75142913在线留言
【PHP进阶】一文搞懂面向对象编程之类(Class)的使用与知识_PHP技术_网络人

【PHP进阶】一文搞懂面向对象编程之类(Class)的使用与知识

Kwok 发表于:2022-02-09 12:09:56 点击:95 评论: 0

好久没有写关于PHP的文章了,相关基础都比较简单,现在的框架都是面向对象的,对于掌握class类知识的要求很高。所以本文就来总结关于PHP中类的使用与命名空间的进阶知识。

一、类的三大特性

在PHP中,类一个复合型的数据类型,里面包括了属于自己的 常量,变量(称为“属性”)以及函数(称为“方法”)。

1、封装

在PHP中,将我们要使用的功能通过class类封装成一个功能模块,如:MySql数据库操作类、文件上传类、图片切割类、 文章列表分页类等,将要使用的功能以打包的形势归结在一起,这是类的重要特性之一。

<?php
//创建一个网站信息的类
class webInfo
{
    //成员属性
    public string $name;
    public string $URL;
    public string $description;
    public int $age;
    //成员方法
    public function show()
    {
        echo '网站名称:' . $this->name . '<hr />';
        echo '网站地址:' . $this->URL . '<hr />';
        echo '网站介绍:' . $this->description . '<hr />';
        echo '网站年龄:' . $this->age;
    }
}
//实例化类
$mySite = new webInfo();
//设置属性
$mySite->name = '网络人';
$mySite->URL = 'http://www.55mx.com';
$mySite->description = 'http://www.55mx.com';
$mySite->age = 15;
//调用类的方法
$mySite->show();

我们可以将网站的信息封装起来,按照固定的格式对网站的数据进行处理。PHP有三种封装概念:Private私有(子类都不可访问),Protected保护(子类可访问),Public公开。

2、继承

有时候网站比较有特色,我们需要增加一些数据或者功能,又不想破坏原来的数据格式,这里就需要使用到继承。

 

//定义一个55mx的类并继承webInfo的公开属性与方法
//通常情况下我们应该继承"抽象类",而不是直接的类,这里只为了演示。
//webInfo 是我们的父类,被55mx继承,别名:基类或超类。
//55mx称为子类,也可称为派生类。
class 55mx extends webInfo{
    public string $type;
}
$55mx = new 55mx();
$55mx->type = "技术博客";
echo $55mx->type ;

继承可以有效的减少重复的代码,并扩展我们想要的功能。继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。

3、多态

因为PHP中弱类型语言,多态在PHP里表现得不强烈。 多态是指在面向对象中能够根据使用类的上下文来重新定义或改变类的性质和行为。

 

<?php
//定义接口
interface DoYourWork {
  function ICanDo();
}
//定义“猫”的行为
class Cat implements DoYourWork {
  public function ICanDo() {
    echo "猫吃鱼~n";
  }
}
//定义“狗”的行为
class Dog implements DoYourWork {
  public function ICanDo() {
    echo "狗吃肉~n";
  }
}
//定义“奥特曼”的行为
class Altman implements DoYourWork {
    public function ICanDo() {
      echo "奥特曼打小怪兽~n";
    }
  }
//实例化
$cat = new Cat();//猫的实例
$cat->ICanDo();//猫的行为

$dog = new Dog();//狗的实例
$dog->ICanDo();//狗的行为

$altman = new Altman();
$altman->ICanDo(); 

可以看到,我们可以根据“类”的不同,返回自己的特点。这就是多态。多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。

小结:

  • 类和类之间应该是低耦合的(模块独立性强)。
  • 继承通常是继承自抽象类,而不是具体类(使用abstract class定义的类)。
  • 通常直接继承抽象类的具体类只有一层,在抽象类中用protected来限定子类可访问。

二、类属性、常量与方法

在上面的代码示例中已充分的对类属性与类方法进行了展示。我们通过下面的代码理解其概念:

 

<?php
//定义“类”,即:一件事物的抽象特点,并定义包含了数据的形式以及对数据的操作。
class MyClass
{
    //成员变量,定义在类内部的变量。类的变量成员叫做属性,或者叫字段
    public $var = '网络人'; //该变量的值对外是不可见的,但是可以通过成员函数(方法)访问,在类被实例化为对象后,该变量即可成为对象的属性。
    //类常量的默认可见性是 public 。
    const CONSTANT = '我的值一但设置,就不可以修改了';//类的常量,与变量不同的是,常量是固定值,不可修改。
    //注意:类常量可以通过子类重新定义。PHP 8.1.0 起,除非设置为final
    
    //成员函数或方法,定义在类的内部,可用于访问上面的对象的数据。
    public function func()
    {
        echo  '我是一个成员方法,我们可访问成员变量:' . $this->var;
    }
}
$myClass = new MyClass(); //对象 − 是类的实例。
$myClass->func();//调用对象里的方法

三、构造与析构函数

1、构造函数

在一个类中定义一个__construct方法作为构造函数(初始类/实例化时立即执行)。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。

2、析构函数

在一个类中定义一个__destruct(): void方法作为构造函数,它会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行(内存回收)。

和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。

 

<?php
class MyDestructableClass 
{
    //构造函数可传参,无返回值,一般做初始化的工作
    function __construct() {
        print "我是构造函数输入的内容n";
    }
    //析构函数不能传参,无返回值,一般做回收工作
    function __destruct() {
        print __CLASS__ . "被销毁了~";
    }
}
$obj = new MyDestructableClass();

四、类的自动加载

spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。

 

<?php

spl_autoload_register(function ($class_name) {
    require_once $class_name . '.php';//加载$class_name.php文件
});

$obj  = new MyClass1();//尝试加载MyClass1.php
$obj2 = new MyClass2();//尝试加载MyClass2.php

spl_autoload_register将函数注册到SPL __autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。

注意:PHP 8.0.0 之前,可以使用 __autoload() 自动加载类和接口,但 PHP 7.2.0 起弃用,在 PHP 8.0.0 起移除。

五、类的静态成员、方法与范围解析操作符 (::)

  1. 静态(static)关键字:声明类属性或方法为静态,就可以不实例化类而直接访问。可以在实例化的类对象中通过静态访问。
  2. 静态属性:静态属性使用 范围解析操作符 ( :: )访问,不能通过对象操作符( -> )访问。
  3. 静态方法:由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
  4. 范围解析操作符
  5. (也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。当在类定义之外引用到这些项目时,要使用类名。
  6.  演示代码:
<?php
class MyWeb
{
    public static $name = '55mx.com'; //静态属性
    //静态方法
    public static function getVule()
    {
        return self::$name;
    }
    //非静态方法,需要先new才能使用
    public function getStaticValue()
    {
        return self::$name . PHP_EOL;
    }
}
echo '静态访问:' . MyWeb::$name . PHP_EOL; //直接使用静态属性
echo '静态调用:' . MyWeb::getVule(); //直接使用静态方法

echo '错误调用:' . MyWeb::getStaticValue(); //错误使用了非静态方法

$neter = new MyWeb(); //实例化
echo '实例化后输出:' . $neter->getStaticValue();//实例化后使用

关于static的作用和好处

  1. static方法就相当于普通的方法一模一样,但是给方法分了个类。语义化代码。
  2. 实例化class时不会重新将static方法声明第二遍。
  3. 静态方法不需要所在类被实例化就可以直接使用。
  4. 静态方法效率上要比实例化高,静态方法的缺点是不自动进行销毁,而实例化的则可以做销毁。
  5. 静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存。

六、抽象类与抽象方法

当一个类中,有一个抽象方法的时候,这个类就必须使用abstract关键字定义为抽象类。 且不能被实例化(只能被继承使用)。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。继承一个抽象类的时候,子类必须实现父类中的所有抽象方法。

 

<?php
//因为包括了抽象方法,所以必须定义成抽象类
abstract class WebInfo
{
    // 强制要求子类定义这些方法
    abstract protected function getSiteName(); //抽象方法
    abstract protected function getURL($url); //抽象方法

    // 普通方法(非抽象方法)
    public function printOut()
    {
        echo $this->getSiteName() . "n" . $this->getURL('www.55mx.com');
    }
}
//抽象类里有未实现的抽象方法,所以我们不能直接使用的
//$myWeb = new WebInfo();//报错: Cannot instantiate abstract class
//使用抽象类做为父类
class myWeb extends WebInfo
{
    //实现抽象方法 getSiteName()
    protected function getSiteName()
    {
        return "网络人";
    }
    //实现抽象方法 getURL()
    protected function getURL($url)
    {
        return "网址:" . $url;
    }
}
$myWeb = new myWeb(); //实例化
$myWeb->printOut();//调用抽象类里的方法

下面会讲到接口,他们有一些共同点:

  1. 都是用于声明某一种事物,规范名称、参数,形成模块,未有详细的实现细节。
  2. 都是通过类来实现相关的细节工作。
  3. 语法上,抽象类的抽象方法与接口一样,不能有方法体,即{}符号
  4. 都可以用继承,接口可以继承接口形成新的接口,抽象类可以继承抽象类从而形成新的抽象类。

抽象类的特点:

  1. 抽象类可以不写抽象方法。
  2. 抽象类内,即便全是具体方法,也不能够实例化,只要新建类来继承后,实例继承类才可以。
  3. 抽象是编程解决问题的基础,越复杂的问题,越需要一开始就对问题进行抽象,而不是直接写代码。

七、接口与抽象方法

接口与抽象类有一点类似,其主要基于方法的规范,会抽象类里的抽象方法,只是其相对于抽象方法来说,更加独立。可让某个类通过组合多个方法来形成新的类。由于接口(interface)和类(class)、trait 共享了命名空间,所以它们不能重名。

接口就像定义一个标准的类一样,通过 interface 关键字替换掉 class 关键字来定义,但其中所有的方法都是空的。接口中定义的所有方法都必须是 public ,这是接口的特性。

 

<?php
//通过接口重写上面的抽象类
interface WebInfo
{
    public function getSiteName(); //抽象方法
    public function getURL($url); //抽象方法 
    public function printOut();//抽象方法
}
//实现接口
class myWeb implements WebInfo
{
    //实现接口里的抽象方法 getSiteName()
    public function getSiteName()
    {
        return "网络人";
    }
    //实现接口里的抽象方法 getURL()
    public function getURL($url)
    {
        return "网址:" . $url;
    }
    //实现接口里的抽象方法 printOut()
    public function printOut()
    {
        echo $this->getSiteName() . "n" . $this->getURL('www.55mx.com');
    }
}
$myWeb = new myWeb(); //实例化
$myWeb->printOut();//调用方法

在其它语言里,接口的别名叫“协议”,所以接口定义的是我们商量好了,要去实现的功能。比如:车应该有转向功能、运动功能、计算速度功能、刹车功能等,我们在接口里将这些功能定义好,使用class定义一个皮卡车、小汽车、公交车类并使用接口,那么我们就需要在类里去实现接口里定义好的抽象方法。

抽象类与接口的不同点:

  1. 接口不能有属性、普通方法、但可以有常量
  2. 接口内一定会有“抽象”方法
  3. 语法上有不同,对接口的使用方式是通过关键字implements来实现的,而对于抽象类的操作是使用类继承的关键字exotends实现的,使用时要特别注意。
  4. 抽象类用abstract关键字在类前声明,且有class声明为类,接口是用interface来声明,但不能用class来声明,因为接口不是类。
  5. 抽象类的抽象方法一定要用abstract来声明,而接口则不需要。

接口的特点:

  1. 接口可以让一个类一次性实现多个不同的方法。
  2. 接口本身就是抽象的,但注意不是抽象类,因为接口不是类,只是其方法是抽象的。所以,其也是抽象的。
  3. 接口中的所有方法都要求是抽象方法。
  4. 接口没有数据成员,但是抽象类有数据成员,抽象类可以实现数据的封装。
  5. 接口没有构造函数,抽象类可以有构造函数。
  6. 接口中的方法都是public类型,而抽象类中的方法可以使用private、protected或public来修饰。
  7. 一个类可以同时实现多个接口(使用","隔开),但是只能实现一个抽象类。

抽象类vs接口的总结:

上面的抽象类和接口的例子,看上去是不是类似?事实上,对于PHP编程来说,抽象类可以实现的功能,接口也可以实现。

抽象类和接口的区别重点不在于编程实现,而在于程序设计模式的不同。

一般来讲,抽象用于不同的事物,而接口用于事物的行为。

七、常用功能

  1. instanceof关键字:分析一个对象是否是某一个类的实例或子类或是实现了某个特定的接口。
  2. 确定类是否存在:boolean class_exists(string class_name): class_exists(‘test');
  3. 返回类名:string get_class(object),成功时返回实例的类名,失败则返回FALSE
  4. 了解类的公用属性:array get_class_vars(‘className') ,返回关键数组:包含所有定义的public属性名及其相应的值。这个函数不能用实例名做变量
  5. 返回类方法:get_class_methods(‘test'); //或: get_class_methods($a);可用实例名做参数,返回包括构造函数在内的所有非私有方法。
  6. print_r(get_declared_classes())了解当前PHP版本中所有的类名。
  7. get_object_vars($a)返回实例中所有公用的属性及其值的关联数组。
  8. 返回父类的名称:get_parent_class($b);
  9. 检测接口是否存在:boolean interface_exists($string interface[,boolean autoload]).
  10. 检测对象类型: boolean is_a($obj,'className')。
  11. 确定是否是某类的子对象:boolean is_subclass_of($b,'test')。
  12. 确定类或实例中,是否存在某方法。method_exists($a,'getv') ,此函数适用于非public定义的作用域的方法。。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/193
标签:PHPclass命名空间Kwok最后编辑于:2022-02-09 18:09:17
0
感谢打赏!

《【PHP进阶】一文搞懂面向对象编程之类(Class)的使用与知识》的网友评论(0)

本站推荐阅读

热门点击文章