PHP类的秘密(一) Why, What and How

281 阅读5分钟

其实这世上本没有类和对象,代码码多了,也就有了类和对象.

为什么要用到类和对象?

自从2002年的第一场雪...IT在各个领域的应用越来越多, 程序越来越复杂, 其中存在大量的重复或类似的功能, 造成大量的函数复用, 代码复用.

为了降低代码的复杂度, 让结构更清晰, 更高效, 越来越多的程序员开始将重复的部分提取出来作为公共模块, 并进行抽象, 抽象出一些公共属性, 公共方法, 公共规则, 将这些抽象的内容进行整合, 就有了类的雏形.

在类的基础上, 针对不同的应用场景, 再去做一些适应性调整, 就产生了继承. 再将不同应用场景的的数据导入, 也就产生了不同的实例(instance).

而且面对越来越复杂的业务, 程序的耦合性越来越高, 维护起来越来越难. 类的应用就很好的满足了将程序解耦, 打散再组装的需求. 让程序员们保住了饭碗, 也保住了头发.

并且, 随着面对对象编程思想的越来越流行, 类这种将事物抽象化的方法获得了巨大的青睐和广泛的应用.

什么是类和对象?

类很简单. 它将一类事物的属性和功能提炼了出来, 并进行定义. 创建类的过程也就是将事物抽象化的过程.

事物的属性通过参数(常量,变量)表达, 事物的功能通过方法(函数)表达. 而将这种抽象化的定义再此实例化, 具现化, 就产生了"对象"(object).

比如,"汽车"这个类, 品牌, 尺寸, 重量, 材料, 颜色, 马力, 油耗, 这些是车的属性, 而前进,后退, 导航, 转向, 这些是他的功能. 而比亚迪-唐, 沃尔沃-S80是它的实例.

类分为:普通类class, 抽象类abstract class, 接口类interface, 内置类stdClass, 子类class extends, 匿名类等.

先说平平无奇-普通类:

  1. 可以实例化, 创建对象.
  2. 可以定义各种类型的变量,常量和方法.
  3. 可以继承一个父类, 也可以被多个子类继承.

我们来看看如何创建一个普通类.

HOW

创建一个普通类很简单:

`class Classname {

}`

上面就完成了一个类的创建, 它可以是空的, 不表示任何意义.

类创建后,我们可以使用 new 运算符来实例化该类的对象.

$C= new Classname;

类和对象都创建完毕, 但如果想让它发挥意义, 就需要包含类构成的3个基本的元素: 成员变量(属性), 成员方法(函数), 类常量. 我们详细看一下.

属性

类的变量成员叫做“属性”. 它用来保存信息数据, 并且与成员方法(函数)进行交互来实现具体功能. 我们通常称呼属性为成员变量.

创建类的属性是我们第一个要做的事情, 属性值可以为空, 也可以有初始值,但是初始化的值必须是常数.

继续在上面的例子扩充属性:

class Classname          //定义一个类, 类名不区分大小写
{
public $name;    //定义成员变量, 公开可见public;
public $height=180;    //初始化赋值
public $weight, $nationality; //可以一个语句定义多个变量
protected $age;      //受保护的变量protected
}

调用成员变量主要通过两种方式, 一个是在成员方法中调用, 另一个是通过对象加->进行调用, 比如:

echo $C->height; // 180, 输出属性值;

echo $C->name='John'; // 'John', 通过对象调用, 为属性赋值;

我们已经能通过定义属性来做一些基本的事情了, 注意在定义属性的时候, 我们会加上一些关键词, 如public, protected, private, 这是标明这个属性的可见度.

成员变量的可见度:

  1. public: 完全公开, 在类定义内部, 外部, 都可以被访问

  2. private: 私有, 只有在本类的内部才能访问, 不可以在类外被访问,在子类中也不可以被调用或修改

  3. protected: 受保护的, 可以被其自身以及其子类和父类访问

  4. 如果什么都不写, 则系统默认为public

我们在声明属性的时候, 还可以限制属性的数据类型, 比如:

class Classname          
{
public string $name;    //限制为字符串格式
public ?int $height    //int型或null
}

在数据类型前面加问号, 表示该变量可以为int型, 也可以为null, 当变量为null时系统不会报错. 这里要注意, null不是不需要赋值, 而是可以赋空值null, 这里null不是undefine的意思.

方法

它是定义在类的内部的函数, 负责具体功能的实现. 通常称它为成员方法. 可用于访问和操作对象数据。

创建成员方法和函数很类似, 成员方法也有可见度, 和成员变量一样, 在上面例子的基础上扩展成员方法:

class Classname          //定义一个类, 类名不区分大小写
{
public $name;    //定义成员变量, 公开可见;
public $height=180;    //初始化赋值
public $weight, $nationality; //可以一个语句定义多个变量
protected $age;

public function player($name,$height, $weight, $age, $sex)
{       //定义成员方法, 以及方法形参
    $this->name=$name;                 //为成员变量赋值, 使用了伪变量$this
    $this->weight=$weight;
    $this->height=$height;

    if ($this->height<185 && $this->weight<=85){
        return $this->name.',符合要求';
    }else{
        return $this->name.',不太行';
    }
}
}

调用成员方法与调用属性类似, 这里的变量名换成了方法名, 并携带指定参数:

$C=new Classname(); //定义一个对象, 关键词new

echo $C->player('小明','185','80','20','male'); //对象调用成员方法

从上面这个例子, 我们可以看出:

  1. 成员变量定义, 可以有初始值, 可以通过一个语句定义多个变量. 还可以定义不同可见度的变量;
  2. 方法定义与普通函数基本类似, 方法内部, 可以通过->符号来引用成员变量;
  3. 在成员方法中调用变量, 用到了$this. 它是一个到当前对象的引用。在上例中, 它引用的就是$C这个对象, 因为方法会被多个对象调用, 所以$this是个调用对象的代词.
  4. 可以通过new关键词来创建对象;
  5. 可以通过对象->来调用方法,并携带实参;
  6. 可以通过对象->来访问public变量;

在定义成员方法参数的时候, 我们还会看到一种特殊的类型:

class Classname
{
    function obj(Classname $a): static {}    
}

这种将类名放到参数中的类型声明, 其实是要求带入成员方法的变量, 必须是该指定类的对象. 类似的还有self, 表明参数必须是方法所在类的一个对象。

而小括号后面的是成员方法的返回类型, static表示返回值必须是成员方法所在类的对象, 这种语法在PHP 8.0开始生效.

今天我们讲了先创建了对象, 然后再通过方法player()来为成员变量赋值. 那么有没有方法能在创建对象的同时, 就完成对成员变量的赋值呢? 当然可以, 这就是"构造函数"的意义. 我们下一节来具体讲.

我最后再针对成员方法补充一点, 成员方法和普通函数有什么不一样么?

  1. 意义上讲: 外部函数实现的是某个独立的功能, 而成员方法是实现类中的一个行为.

  2. 调用: 函数可以在全局直接调用, 而成员方法需要被对象调用, 或通过类进行调用.

  3. 操作对象: 外部函数可以操作全局和其内部变量, 常量等. 而成员方法只能操作所属类的成员变量或调用其他成员方法.

但在一些特殊场景下, 他们也可以实现互相调用, 我这里举个例子, 但我个人不太建议这么做:

function rrc($rrc)       //定义一个外部函数
{
    echo $rrc;
}                   

class Rrc
{
    function bbc()        //定义一个成员方法, 并直接引用外部函数;
    {
    rrc('test');
    }
    
    function vcc()       //定义一个成员方法;
    {
    echo 'done';
    }
}
$ccc=new Rrc;         
$ccc->bbc();        //输出test, 实现了成员方法对外部函数的引用;
function dcc()      //定义一个外部函数, 用来引用类成员方法;
{
$GLOBALS['ccc']->vcc();  //通过$GLOBAL可以引用到对象$ccc, 并通过对象调用方法;
}
dcc();     //输出done, 调用成员方法成功;

好了, 第一节基础课就讲到这里, 下课~!

总结不易, 请勿私自转载, 否则别怪老大爷不客气!

参考资料:

www.php.net PHP官方文档

零基础PHP学习笔记 明日科技