PHP七天系列之面向对象

历史


早期编程由于受电脑硬件限制,程序都是追求效率,而忽略可理解性,扩充性,随着硬件技术的发展,编程越来越重视多人开发,程序员越来越重视程序的可靠性,可扩展性,可维护性,所以刺激了程序语言的发展

面向过程

  • 程序员设计好程序代码流程图,辅助程序设计。优点:用什么功能就编写什么函数 缺点:数据管理上比较混乱 ,主要集中在函数成面上,面向对象把属性和方法进行封装,更好的可重用性和可扩展性

面向对象

  • 万物皆对象,将构成问题的事务分解到各个对象上,建立对象的目的不是为了完成一个工作,而是为了描述某个事务在解决问题中的行为,更符合人的思维习惯,代码重用性高,可扩展性好

面向对象和面向过程的核心区别是如何分配职责。

类和对象


面向对象是由一系统具有属性和方法的对象构成,对象之间相互交互 ,从而实现业务需求。
属性

  • 在类中定义的变量,即为成员属性,用于描述对象静态特性的数据。如人的姓名,性别,首字母小写
    方法

  • 函数定义在类中即为成员方法,用于描述对象动态特性的操作行为,方法名不区分大小写,不可重名,首字母小写

对象生命周期

  • 创建后,生命周期开始,当程序结束后或程序员清除对象后即销毁,PHP会自动销毁对象

类是一种抽象的概念,是具有相同语义定义对象的集合(具有相同属性和方法的集体),使用具体的类是不可行的,只能实例化。拿汽车举例,汽车的设计图纸就是类,汽车是对象。设计中重点是类的创建

类名书写规范

  • 类名首字母大写
  • 一个类定义在一个文件中

$this

对象中使用 $this 指针可以访问属性或方法。

class Code
{
    protected $len = 5;
    public function make()
{
        return $this->len . $this->show();
    }
    public function show()
{
        return ' : is show';
    }
}
echo (new Code)->make();

继承

通过使用 extends 可以继承父类的属性与方法,在PHP中继承是单一的。

class Notify
{
    public function message()
{
        return 'notify message';
    }
}
class User extends Notify
{ }
echo (new User)->message();

父类调用

子类可以使用 parent 关键字调用父类方法

...
public function message()
{
return parent::message();
}
..

方法重写

子类可以重写父类的方法,除非父类的方法没有使用 final 修饰。

class Notify
{
    public function message()
{




        return 'notify message';
    }
}
class User extends Notify
{
    public function message()
{
        return 'user notify';
    }
}
echo (new User)->message();

禁止重写

使用final声明的方法,将禁止在子类中重写父类方法。

public final function message()
{
return 'notify message';
}

封装

public 公有

  • 在类的内部与外部或子类都可以访问,是最开放的权限

private 私有

  • 定义类的属性和方法,在类的内部可以访问,在类的外部或子类都不可以访问

protected 受保护

  • 定义类的属性和方法,在类的内部或子类可以访问,类的外部不可以访问

模块设计

  • 强内聚(功能尽量在类的内部完成),弱耦合(开放尽量少的方法给外部调用)。例:公司销售接项目,具体工作交给公司内部程序员,设计人员,服务器管理人员协同完成

trait


使用 trait 机制可以变相的使用多重继承。

class Alipay
{
    use Pay;
}
class WePay
{
    use Pay;
}

trait Pay
{
    public function sn()
{
        return 'ABCDEF';
    }
}
echo (new WePay)->sn();

如果本类与 trait 中存在同名的属性和方法时,将使用本类中的属性与方法。

...
class WePay
{
    use Pay;
    public function sn()
{
        return __METHOD__;
    }
}

trait Pay
{
    public function sn()
{
        return 'ABCDEF';
    }
}
...

多个trait

可以使用多个 trait 用逗号连接

...
use Pay,Site;
...

解决冲突

class WePay
{
    use Pay, Email {
    Pay::notify insteadof Email;
    Email::notify as EmailNotify;
}
trait Pay
{
    public function notify()
{
        return __METHOD__;
    }
}
trait Email
{
    public function notify()
{
    return __METHOD__;
    }
}
echo (new WePay)->notify();

Pay::notify insteadof Email 表示使用 Pay::notify 方法替代 Email::notify 方法。
Email::notify as EmailNotifyEmail:notify 别名为 EmailNotify

访问控制

可以为继承的 trait 方法重新定义访问控制

class WePay
{
    use Pay, Email {
    Pay::notify insteadof Email;
    Email::notify as protected EmailNotify;
    ...
}

多重trait

可以通过多个 trait 组合来使用。

trait Notify
{
    public function response()
{
        return 'notify response';
    }
}
trait Pay
{
    use Notify;
}

class User
{
    use Pay;
}
echo (new User)->response();

抽象方法

trait Notify
{
    public function response()
{
        return 'notify response' . $this->sn();
    }
    abstract protected function sn();
}
trait Pay
{
    use Notify;
}

class User
{
    use Pay;
    protected function sn()
{
        return 'SN999';
    }
}
echo (new User)->response();

静态方法

trait 中可以使用静态方法、抽象方法、静态属性。

...
trait Pay
{
    public function sn()
{
        return 'ABCDEF';
    }
    public static function notify()
{
        return __METHOD__;
    }
}
class WePay
{
    use Pay;
    ...
}
echo WePay::notify();

static


static:

  • 需要一个数据对象只服务于类,即类内部可用,对外不可用时。建对象是极其耗费资源的,因此当一个方法具有比较强的公用性的时候,没有必要为了调用这个方法而重新再生成该类的实例。定义的方法或变量在程序第一次加载时即驻留内存,程序结束释放。

static变量:

  • 通过static声明的成员变量为静态变量或叫类变量,是该类的公共变量,在第一次使用时即生成,对于该类的所有对象只有一份,是属于类的,不是属于对象的。static变量是属于类而不属于对象,可以在任何地方通地类来访问,是类的全局变量,类创建时即存入内存。对多个对象来说,静态数据成员只存储一处,可以节省内存。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值。

static方法:

  • 用static声明的方法为静态方法或叫类方法,执行该方法时不会将对象引用传给函数,所以我们不能访问非静态成员,只能访问静态方法或静态变量。只能使用关于类的方式如self static parent等。使用时不用生成对象即可执行

类常量


使用 const 来定义类常量,常量使用 self:: 来调用。

class Model implements ArrayAccess, Iterator
{
    use ArrayIterator, Relation, Validate, Auto, Filter;
    //----------自动验证----------
    //有字段时验证
    const EXIST_VALIDATE = 1;
    //值不为空时验证
    const NOT_EMPTY_VALIDATE = 2;
    ...
}

$this self:: parent::

$this

  • 是当前对象的引用, 一般出现在方法里,用于获取类的成员属性,或执行类的成员方法

self::

  • 对本类的引用 ,用于获取当前类的表态成员属性或静态成员方法self::run()

parent::

  • 对父类的引用,调用父类的方法或属性。

魔术方法


构造方法&析构方法

构造方法__construct()

  • 在创建对象时自动执行,没有返回值,用于执行类的一些初始化工作,如对象属性的初始化工作,构造方法为__construct()。
  • 可以在构造方法中传递参数,用于定义属性,在父类和子类都定义构造方法时,执行子类的构造方法

析构方法__destruct():

  • 当所有对象的引用被销毁时执行。

__get 与__set

读取不可访问或不存在的属性时,_get() 会被调用,同理获取不可访问或不存的的属性时会执行 _set() 方法。

<?php
abstract class Query
{
    abstract protected function record(array $data);
    public function select()
{
        return $this->record(['name' => 'PFinal社区', 'age' => 33]);
    }
}
class Model extends Query
{
    protected $field = [
        'name'
    ];
    public function all(){
      $this->select();
      return $this->field;
    }
    protected function record(array $data)
{
        $this->field = $data;
    }
    public function __get($name)
{
        return $this->field[$name] ?? null;
    }
    public function __set($name, $value)
{
        $this->field[$name] = $value;
    }
}

$user = new Model;
$user->all();
echo $user->name;
$user->name = 'PFinal南丞大叔';
echo $user->name;ry

_isset() 与 _unset()

当使用 isset()函数或者empty()函数 判断属性是否存在或者是否为空的时候会自动触发。
当使用 unset() 函数判断属性时,如果存在__unset() 方法将会执行。

...
public function __unset($name)
{
if (!isset($this->field[$name]) || in_array($name, $this->deny)) {
        throw new Exception('禁止操作');
}
}
public function __isset($name)
{
return isset($this->field[$name]);
}
...

抽象类&抽象方法


具有抽象方法的类为抽象类,抽象方法即为没有内容的空方法,要求子类进行完善内容,抽象类不能实例化,只能继承,通过extends来实现,抽象类中也可以定义普通方法

父类方法执行方式不确定,但子类还都有这个方法

例1:如交通工具类:定义抽象方法控制交通工具运行方式,这样每个交通工具如飞机,汽车都要重写父类方法。如果在父类工具类定义该方法(比如在地上走)没有任何意义,因为每个交通工具都要重写(飞机要重写方法,船要重写方法),所以针对你类方法的不确定性,我们需要抽象方法,实现多态。

例2:定义动物类,每个动物都有叫声方法,但是表面不同,所以要定义为抽象类,让每种动物类去实现功能。

  • 当父类为抽象类时,子类必须重写父类的抽象方法
  • 抽象类里不一定非要写抽象方法,但有抽象方法的类必须定义为抽象类
  • 抽象类必须继承使用
  • 抽象方法不能有主体即{}
<?php

abstract class AbstractClass
{
   // 强制要求子类定义这些方法
abstract protected function getValue();

abstract protected function prefixValue($prefix);

   // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue();

    }
}

接口


接口是一组成员声明方法的集合,包含空的成员方法和常量,空的方法要求继承类去具体实现。成员方法为public,属性为常量。

  • 例如:现实中的电脑USB或PCI插槽,插线板等都有接口例子

继承是一级一级层次式,如果某一层出现问题,整个继承就会出现意外。而接口只影响实现接口的类,接口可以在破坏原来的继承基础上对类扩展。接口可以实现多继承。

  • 例:电脑USB接口,规定各个厂商必须构造合适的接口方法,比如手机,数码相机,网银U盾。要让各个厂商写自己的方法如U盾插到USB上他会自动安装网银驱盾,弹出网页,手机装上后可以打开手机里的内容,同时可以充电

抽象类及普通类都可以实现接口,通过关键字implements

接口与抽象类的区别:

  • 1 接口只能用implements实现 抽象类用extends继承实现
  • 2 接口没有数据成员,可以定义常量,抽象类可以有
  • 3 接口没有构造函数,抽象类可以定义构造函数
  • 4 接口方法都是public 抽象类方法可以用protected private public来修饰
  • 5 一个类可以实现多个接口,但只能继承一个抽象类
  • 6 接口中不可以有成员方法,抽象类可以有成员方法
interface DbInterface {
    public function connectDb(); //获得连接   参数为表名
    public function close(); //关闭数据库
    public function exe($sql); //发送没有返回值的sql
    public function query($sql); //有返回值的sql
}
class Db implements DbInterface
{
public function exe($sql){
}
public function query($sql{
}
}
``  
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,049评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,478评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,109评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,097评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,115评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,280评论 1 279
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,748评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,398评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,553评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,440评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,487评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,176评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,750评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,821评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,049评论 1 257
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,559评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,150评论 2 341

推荐阅读更多精彩内容