78. 对象与类的简介
对象和数组的区别,对象不仅可以存储多个数据,还可以存储函数。
什么是对象?
世间万物皆对象,对象就是一个实体,在生活中可以描述出来的东西。如:电脑、桌子、小鸟。
对象中有什么?
对象有属性,如:小鸟有翅膀,有嘴巴。。。
对象有方法,如:小鸟会飞,小鸟会吃东西。。。
什么是类?
类是对象的模型,每一个对象都是根据一个类造出来的。类是对象的声明,对象是类的实例。类是抽象的,代表一类事物,现实生活中的具体事物。
OOP,面向对象编程,达到了代码变编程的重用性、灵活性和可扩展性。
面向过程,项目最小单位由函数组成。
面向对象,项目最小单位由对象组成。
79. 对象声明与使用
类的声明:
修饰符 class 类名{
成员
}
实例化对象:
变量 = new 类名();
<?php
class Bird{
public $wing = 2;
public function fly(){
if($this->wing >= 2){
echo '可以飞';
}else{
echo '飞不了';
}
}
}
class Doctor{
public function fixed($bird){
$wing = (int)mt_rand(1, 2);
$bird->wing = $wing;
}
}
$bailu = new Bird();
$wang = new Doctor();
echo $bailu->wing;
echo '<br>';
$bailu->fly();
echo '<br>';
$wang->fixed($bailu);
echo $bailu->wing;
echo '<br>';
$bailu->fly();
?>
80. 构造函数、析构函数
__construct(),构造函数,在实例化对象时自动调用,一般用于初始化对象。
__destruct(),析构函数,销毁对象或对象使用完毕时调用,一般用于释放内存等操作。
例:
class Human{
public $name;
public $gender;
public function __construct($name, $gender){
$this->name = $name;
$this->gender = $gender;
echo '对象构造完毕';
}
public function sayHi(){
echo 'Hello, my name is '. $this->name;
}
public function __destruct(){
echo '该对象已经被销毁';
}
}
$zhangsan = new Human('张三', '女');
$zhangsan->sayHi();
// unset($zhangsan); // 手动销毁对象
总结:
- 构造函数,__construct(),可以有参数,以便初始化对象
在 new 对象时,自动执行。
new 对象时,
① 申请内存
② 如果有构造函数,先执行构造函数
③ 返回该对象的地址 - 析构函数,__destruct()
对象销毁时,执行。一般在文件最后会自动销毁对象,也可以手动销毁。
对象销毁:
$a = new Human();
$a 并不是对象,它只是一个变量名,指向对象。unset($a) 未必销毁了对象,一个对象如果还有其它变量来引用,unset($a) 并不会销毁,当引用为0,对象才销毁。 - $this 意义
$this 指向调用方法的对象。
$a->sayHi()、
sayHi(){} 函数体内的 $this->name
注:方法内,存取对象的属性值时,必须用 $this。
81. 面向对象之封装性
封装性,把对象成员属性、成员方法结合在一起,形成一个不可分割的独立单元,把这个独立单元的内部细节对外隐藏起来,对开放有限的接口供外界访问使用。
<?php
class Human{
private $money = 1000;
private $bank = 2000;
// 从银行里面取钱
private function getBank($n){
if($n <= $this->bank){
$this->bank -= $n;
return $n;
}
return 0;
}
// 借钱给别人
public function send($much){
if($much <= 1000){
$this->money -= $much;
}elseif($much <= $this->money + $this->bank){
$num = $much - $this->money;
$this->money += $this->getBank($num);
$this->money -= $much;
}else{
echo '对不起,钱不够';
return false;
}
return $much;
}
}
$lisi = new Human();
$m = $lisi->send(300);
if($m){
echo '借了'. $m .'元';
}
?>
如何判断属性、方法 有没有访问权限?
看访问位置:
private 只能在类定义的大括号 {} 内,才能访问。
public 在任意位置都可以用对象访问。
82. 封装mysql类
<?php
error_reporting(0); // 把错误报告等级设置为0
class mysql{
private $host;
private $user;
private $pwd;
private $dbname;
private $charset;
private $conn = NULL; // 连接资源
// 构造函数,初始化
public function __construct(){
$this->host = 'localhost';
$this->user = 'root';
$this->pwd = 'root';
$this->dbname = 'test';
$this->charset = 'utf8';
$this->connect($this->host, $this->user, $this->pwd);
$this->switchDb($this->dbname);
$this->setchar($this->charset);
}
// 连接数据库
private function connect($h, $u, $p){
$conn = mysql_connect($h, $u, $p);
$this->conn = $conn;
}
// 发送命令
private function query($sql){
return mysql_query($sql, $this->conn);
}
// 换库
public function switchDb($dbname){
$sql ='use '. $dbname;
return $this->query($sql);
}
// 选字符编码
public function setchar($char){
$sql = 'set names '. $char;
$this->query($sql);
}
// 取全部数据
public function getAll($sql){
$list = array();
$rs = $this->query($sql);
if(! $rs){
return false;
}
while($row = mysql_fetch_assoc($rs)){
$list[] = $row;
}
return $list;
}
// 取一行数据
public function getRow($sql){
$rs = $this->query($sql);
if(! $rs){
return false;
}
$row = mysql_fetch_row($rs);
return $row[0];
}
// 关闭连接
public function close(){
mysql_close($this->conn);
}
}
$mysql = new mysql(); // 实例化MySQL类
// 查询前十位客户的名字
$sql = 'select cu_name from customer limit 10';
$result = $mysql->getAll($sql);
var_dump($result);
// 查询客户的平均年龄
$sql = 'select ceil(avg(cu_age)) from customer';
$result = $mysql->getRow($sql);
var_dump($result);
?>
83. 面向对象之继承性
子类 extends 父类{}
- 只能继承自一个父类。
- 对于子类继承父类的 protected / public 属性、方法:
- 父类有的,子类继承
- 父类有的,子类可以更改
- 父类没有的,子类可以添加
- 子类继承父类的 private 属性、方法:
可以继承过来,但无权修改。
继承后,权限只能越来越宽松或不变,不能严格。
构造方法也可以继承,继承原则和普通方法一样。
如果子类也声明构造方法,则父类的构造方法被覆盖了。
如果父类的构造方法被覆盖了,自然,只执行子类中的新的构造方法。
如果是一个数据库操作类,或者model类,肯定是继承过去再用,不能直接操作model类。而model类又做了许多初始化的工作。
重写的model类的构造方法,导致初始化工作完不成时,如果子类继承时,子类有构造,为了保险起见,先调用父类的构造,例:
parent::__construct();
public、private、protected 权限:
private | protected | public | |
---|---|---|---|
本类内 | √ | √ | √ |
子类内 | √ | √ | |
外部 | √ |
84. 面向对象之多态性
多态性,是指不同类的对象对同一事件作出不同的响应。即,同一个操作根据不同的操作对象而产生不同的效果。
<?php
class Light{
public function open(Glass $g){
$g->display();
}
}
class Glass{
public function display(){
echo '发光';
}
}
class RedGlass extends Glass{
public function display(){
echo '照红光';
}
}
class BlueGlass extends Glass{
public function display(){
echo '照蓝光';
}
}
class GreenGlass extends Glass{
public function display(){
echo '照绿光';
}
}
$light = new Light();
$red = new RedGlass();
$blue = new BlueGlass();
$light->open($red);
$light->open($blue);
?>
85. 静态属性/方法
在属性和方法前,加 static 修饰,这种称为静态 属性/方法。
普通属性包在类内,用 对象->属性名 访问。
静态属性在类内,类声明完毕,该属性就已存在,不需要依赖于对象而访问。类在内存中只有一个,因此,静态属性也只有一个。
普通方法存放在类内,只有一份,需要对象去调用,属于对象,需绑定 $this 。
静态方法存在于类内,只有一份,不属于哪个对象,属于类。因此,不需要去绑定 $this ,通过类名就可以调用。
类 —— 访问 静态方法 ,可以
类 —— 方位 动态方法 ,方法内没 this 的情况下,但严重不支持,逻辑上解释不通
对象 —— 访问 动态方法,可以
对象 —— 访问 静态方法,可以
<?php
class A{
function foo(){
if(isset($this)){
echo '$this is defined (';
echo get_class($this);
echo "). \n";
}else{
echo '$this is not defined. \n';
}
}
}
class B{
function bar(){
A::foo();
}
}
$a = new A();
$a->foo(); // foo 是普通方法, $a 绑定到 $this ,属于 A类
A::foo(); // 这样调用不规范,不绑定 $this
$b = new B();
$b->bar(); // bar 是普通方法, $b 绑定到 $this , b(){A::foo()} 这里静态调用,不操作 $this
B::bar(); //不绑定 $this
?>
86. self-parent
self 当前类(不是本对象)
parent 当前类的父类
例:
<?php
class cHuman{
static public $money = 100;
public function say(){
echo Human::money;
}
}
class customer extends cHuman{
static public $money = 1000;
public function say(){
echo self::$money;
echo '<br>';
echo '父类只有', parent::$money;
}
}
$zhangsan = new customer();
$zhangsan->say();
?>
从上面代码的运行结果,可以看出,self 和 parent 是有区别的。
再如:
<?php
class A{
public function a1(){
echo 'this is class function a1';
}
}
class B extends A{
public function b1(){
echo $this->a1();
}
public function b2(){
echo parent::a1();
}
}
$b = new B();
$b->b1();
$b->b2();
?>
显示效果一样,但从面向对象角度看,继承过来的,就是自己的, $this 更符合面向对象的思想。
87. 单例模式
单例模式是一种常见的设计模式。核心结构中,只包含一个称为单例的特殊类。通过单例模式,可以保证系统中一个类只有一个实例,即一个类只有一个对象。
实现思路:
① 不让外部通过 new 来实例化:构造器私有化、保护
② 通过内部的 static 方法来调用实例化,并且,把实例保存在类内部的静态属性上
③ 防止对象的克隆:克隆方法私有化、保护
总结:三私一公
<?php
class Single{
public $hash;
static protected $ins = NULL;
final protected function __construct(){
$this->hash = mt_rand(1, 99999);
}
static public function getInstance(){
if(! self::$ins instanceof self){
self::$ins = new self();
}
return self::$ins;
}
}
$s1 = Single::getInstance();
$s2 = Single::getInstance();
var_dump($s1);
var_dump($s2);
if($s1 == $s2){
echo '是同一个对象';
}else{
echo '不是同一个对象';
}
?>
88. final
final 不可修饰属性
final + 方法:可继承,不可重写
final + 类:不能继承自最终的类,即final类不能被继承
<?php
final class Human{}
class stu extends Human{}
// 将报错,因为final类不能被继承
?>
<?php
class Human{
final public function say(){
echo '123';
}
public function show(){
echo '456';
}
}
class Stu extends Human{}
$ming = new Stu();
$ming->say(); // final 方法可以被继承
class FreshMan extends Stu{
public function say(){
echo '789'; // 出错,不可重写
}
}
?>
89. abstract
抽象方法只有声明部分,没有方法体,即,没有 {} 。采用 ‘ ; ’ 结束
一个类中,只要有一个抽象方法,这个类就必须声明为抽象类。
抽象方法在子类中必须重写。
总结:
- 抽象类不能被实例化
- 有抽象方法的类一定是抽象类,类必须用 abstract 修饰
- 抽象方法不能有函数体,即 abstract function foo();
- 抽象类中的非抽象方法,可以被子类调用
- 非抽象子类继承抽象类,子类必须实现父类的全部抽象方法
- 抽象子类继承抽象类,无需继承父类的抽象方法
<?php
abstract class Animal{
public $name = 'animal'; // 有抽象方法的类一定是抽象类;类必须要abstract修饰
abstract function cry(); // 抽象方法不能有函数体
public function getName(){
echo '我的名字';
}
}
// new Animal(); // 报错,抽象类不能被实例化
class Dog extends Animal {
// 非抽象子类继承抽象类,子类必须实现父类的所有抽象方法
public function cry(){
// todo
}
}
$dog = new Dog();
$dog->getName(); //抽象类中的非抽象方法可以调用
abstract class Cat extends Animal{
// 抽象子类继承抽象类,无需继承父类的抽象方法
}
?>
90. 工厂模式
工厂模式,就是把创建对象的过程封装起来,进行工厂化管理。
工厂模式的优点就在于创建对象上。建立一个工厂(一个函数或一个类方法)来制造新的对象,它的任务就是把对象的创建过程都封装起来,创建对象不再是使用new的形式了。而是调用一个方法或函数。
<?php
class A{}
class B{}
function getObj($c){
if($c == 'A'){
return new A();
}elseif($c == 'B'){
return new B();
}
}
?>
91. 魔术方法
、、、、、、、、
名称 | 描述 |
---|---|
__get() | 读取不可访问或不存在属性时被调用 |
__set() | 当给不可访问或不存在属性赋值时被调用 |
__isset() | 对不可访问或不存在的属性调用 |
__unset() | 对不可访问或不存在的属性进行unset时被调用 |
__clone() | 进行对象clone时被调用,用来调整对象的克隆行为 |
__toString() | 当一个类被转换成字符串时被调用 |
__call() | 调用不可访问或不存在的方法时被调用 |
__construct() | 构建对象的时被调用 |
__destruct() | 明确销毁对象或脚本结束时被调用 |
__autoload() | 加载一个未定义类时被调用 |
<?php
function __get($t){
return $this->$t;
}
function __set($t, $a){
$this->$t = $a;
}
function __toString(){
return "name:". $this->name;
}
echo $p;
function __isset($t){
return isset($this->$t);
}
isset($p->name);
function __clone(){}
$p2 = clone $p1;
function __call($fname, $arr){
echo $fname .' 方法不存在';
var_dump($arr);
}
?>