(一):面向对象编程OOP
OOP(Object-Oriented Programming), 面向对象的编程)技术为编程人员敞开了一扇大门,使其编程的代码更简洁、更易于维护,并且具有更强的可重用性
(二):OOP软件的三个目标
重用性 拓展性 灵活性
(三):面向对象编程的三大特性
<b>封装</b>:面向对象的软件的重要优点是封装也叫 ”数据隐藏” 封装就是把对象中的成员属性和成员方法加上修饰符,使其尽可能隐藏对象的内部细节,以达到对成员的访问控制<br />
<b>继承</b>:继承允许子类与类之间创建层次关系,子类将从它的超类(父类)中继承属性和方法,通过继承可以在原有类的基础上创建出新的类,由一个类衍生出更复杂更专门的类,使代码具有更好的重用性,这对于功能的设计和抽象很有用,使其升级和维护更加的灵活。<br />
<b>多态</b>:面向对象的语言必须支持多态
1. 父类被子类继承之后 拥有不同的数据类型和行为表现
2. 一个接口可以有多种不同的实现 ,对应不同的数据类型和行为表现
3. 一个类可以被实例化多个对象,不同对象也有不同的数据类型和表现行为
(四):类和对象的概念
<b>类</b>: 类是对具有相同或者相似特征事物抽象出的描述,其中静态的特征称为“属性”,动态的行为称为“方法”。
1. 类名使用class关键字定义,类名遵从标识符统一规范
2. 类中成员只能包含属性、方法和常量,不能有其他语句块
3. 成员属性必须加上修饰符,成员方法可以不加,默认为public
4. 成员属性可以初始化值 但只能是固定类型值 不能含有运算符或变量
5. 当一个方法在类定义内部被调用时,有一个可用的伪变量 $this 。 $this 是一个到主叫对象的引用
<b>对象</b>:面向对象的软件中,对象几乎可以表示所有的实物对象和概念对象,可以表示物理实际存在的对象:一个人,一棵树等。也可以表示软件中才有的概念对象:一个文件,一个资源等。
<b>类和对象的关系</b>:
1. 类是对象的抽象描述,没有类就不可能有对象,每一个对象必须隶属于某个类。
2. 对象是类的具体体现,没有具体对象的类,毫无意义就是一堆死代码,想发挥一个类的作用,就必须让这个类有对象。
(五):访问控制
对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
本类 | 子类 | 外部 | |
---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 |
protected | 可以访问 | 可以访问 | 不可以访问 |
private | 可以访问 | 不可以访问 | 不可以访问 |
(六):继承的实现
- 一个类可以通过继承拥有另一个类的属性和方法,其中被继承的类称为基类、超类或父类,继承的类称为子类。
- PHP继承是单向的,子类可以从父类或者超类继承特性,父类不可以从子类获取特性
- 子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。
- 继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。
class Human{}
class blackMan extend Human{}
class whiteMan extend Huamn{}
class englishMan extend whiteMan{}
(七):静态属性
使用static修饰的成员为静态成员,只隶属类本身,可以看成是所有对象的 “公有数据” 。
- 静态属性使用类名访问,在类中可以使用self代替类本身 <font color=”blue”>类名::$静态属性名
注释:双冒号::是范围解析操作符, 用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。</font>- 静态方法中不能出现动态内容,即不能有$this这样的内容。
<font color=”blue”>注释:由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用</font>- 如果一个方法中不含有$this则认为这个方法是静态方法,按照严格语法最好在方法体上加上static修饰
- 用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误
- 静态属性不可以由对象通过 -> 操作符来访问。
静态实例
//计算实例化对象的个数
class demo
{
public static $counter;
public function __construct()
{
echo "这是第".++self::$counter."个对象<br />";
}
}
new demo();
new demo();
<br />
//单列设计模式的基本写法
class Single
{
//定义一个静态属性,用于存储一个实例化的对象
private static $instance=null;
//私有化构造方法
private function __construct()
{
//初始化代码
}
//产生对象的方法
public static getObj()
{
if(!isset(self::$instance))
{
$obj = new self;
self::$instance = $obj;
return $obj;
}else{
return self::$instance;
}
}
//私有化魔术克隆方法
private function __clone()
{
//代码
}
}
$obj1 = Single::getObj();
$obj2 = Single::getObj();
var_dump($obj1);
var_dump($obj2);
<br />
//工厂模式部分
class Human{};
class Animal{};
class factory
{
static function getObj($className)
{
$obj = new $className();
return $obj;
}
}
$obj1 = factory::getObj("Human");
$obj2 = factory::getObj("Animal");
(八):覆盖override(也叫:重写)
基本概念:在子类中从父类继承下来的属性或方法重新的“定义”,覆盖掉原有的,等于将原有的方法和属性重新写了一次。
- 重写的基本要求是方法的参数要保持一致。
- 访问权限不能比原有的小(public > protected > privte)
比如:父类中是:public 子类只能是:public;父类中是:protected 子类中可以是:public 和protected
- 私有属性和私有方法不能覆盖,子类中出现同名的方法和属性,就当是子类自己重新定义的。但是方法的参数要保持一致。
- 构造方法的重写,比较宽松,参数可以与父类不一致
class Human
{
public $id;
public $name;
public $sex;
private $age;
protected $addr;
public function __construct($id,$name,$sex,$age,$addr)
{
$this->id = $id;
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
$this->addr = $addr;
}
}
class pre extends Human
{
public $num;
public $nationality;
public $skin;
public function __construct($id,$name,$sex,$age,$addr,$num,$nationality,$skin)
{
parent::__construct($id,$name,$sex,$age,$addr);
$this->num = $num;
$this->nationality = $nationality;
$this->skin = $skin;
}
}
(九):重载overloading
PHP所提供的”重载”(overloading)是指动态地”创建”类属性和方法。我们是通过魔术方法(magic methods)来实现的。
<b>属性重载:</b>
1. public void __set ( string $name , mixed $value )
2. public mixed __get ( string $name )
3. public bool __isset ( string $name )
4. public void __unset ( string $name )
参数 $name 是指要操作的变量名称。__set()方法的 $value 参数指定了 $name 变量的值。
<b>方法重载:</b>
1. public mixed __call ( string $name , array $arguments )
2. public static mixed __callStatic ( string $name , array $arguments )
$name 参数是要调用的方法名称。 $arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。
(十):final关键字
一个类既然能被继承,但是也有类不希望被继承,方法能被重写,但是也有方法不希望被重写,所以需要使用关键字:final
PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承
(十一):对象复制
对象为引用类型,这里赋值类似于起别名,赋值产生的对象是复制的“引用关系,赋值产生的还是同一个对象
通过克隆可以产生一完全独立的对象,使用关键字:clone
仅仅使用clone关键字去克隆一个对象,只能克隆出他的非资源费非对象数据,要完整克隆一个对象,需要使用__clone()魔术方法,在克隆时自动触发
//在外部克隆时,自动触发
public function __clone()
{
$this-> handle = fopne("./readme.txt","r");
}
public function __destruct()
{
fclose($this->handle);
}
}
//实例一个对象
$person1 = new Human("岳飞","male");
//克隆出一个完全一样的对象
$person2 = clone($person1);
(十二):对象信息保存
所有php里面的值都可以使用函数 serialize() 来返回一个包含字节流的字符串来表示。 unserialize() 函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
<b>序列化:serialize() :</b><br /> 用来将对象转化成字符串保存的函数,将转化后的字符串保存至文本或者数据库中,便于跨脚本使用
当对一个对象进行“序列化”操作的时候,会自动调用类中的__sleep()方法
“__sleep()魔术方法中可以进行一些数据(资源)的清理工作,并返回一个数组,该数组可以存储一些想要进行序列化的对象的属性——即可以挑选属性进行序列化。”
//部分代码
//序列化的时候,会自动触发魔术方法__sleep()
public function __sleep()
{
return array("name","sex","handle");
}
public function __destruct()
{
fclose($this->handle);
}
}
$person = new Human("乔峰","male");
$str = serialize($person);
file_put_contents("./readme.txt",$str);
<b>反序列化:unserialize() :</b><br />将序列化后的字符串转换回对象的格式
注释:反序列化时,必须有对应的类声明
“__wakeup()魔术方法中,在进行反序列化操作的时候进行某些必备的“数据恢复工作”,比如:打开某个资源等”
//部分代码
//在反序列化的时候自动调用的魔术方法__wakeup();
public function __wakeup()
{
$this->handle=fopen("./readme.txt","r");
}
public function __destruct()
{
fclose($this->handle);
}
}
$str = file_get_contents("./readme.txt","r");
$obj = unserialize($str);
(十三):自动加载__autoload()
__aotoload()是一个单独的函数不是一个类方法。
__autoload()的主要用途是尝试包含或请求任何用来初始化所需要的类文件。
__autoload()会在实例化一个还没有被声明的类时自动调用
//部分代码片段
function __autoload($classname)
{
require "./libs/{$classname}.class.php";
}
$p = new Human("乔峰","male","35","song");
var_dump($p);
补充:spl_autoload_register()注册给定的函数作为 __autoload 的实现【参看PHP手册】
(十四):抽象类
可以定义不含方法体的方法,即为:抽象方法,需要是使用abstract定义,含有抽象方法的的类,一定是抽象类,必须abstract声明成抽象类
- 抽象方法必须只声明调用方式,不能定义具体功能实现
- 抽象方法不能被设置为私有(不能被private修饰)
- 抽象方法不能有{},直接;结束
- 抽象类不能被实例化
- 继承抽象类的子类,必须定义所有的抽象方法,子类中定义的抽象方法访问控制,不能比抽象类中定义的更严格
- 子类中必须完成继承过来的抽象方法的具体实现,这就是抽象类的约束作用
- 抽象类的约束作用可以有效的做到项目开发中的规范性要求,实现项目管理。
//部分代码
abstract class Human
{
public $name;
public $addr;
public function __construct($name,$addr)
{
$this->name = $name;
$this->addr = $addr;
}
//公有的抽象方法
public abstract function reading();
//受保护的抽象方法
protected abstract function runing();
}
class person extends HUmann
{
public function reading()
{
//抽象方法的实现
}
public function runing()
{
//抽象方法的实现
}
}
(十五):接口
如果在一个抽象类中只包含抽象方法时,我们把该”类”称为接口(interface),它需要单独的类去实现(implements)
<b>基本规则:</b>
1. 接口的所有方法都是抽象方法,但是不需要使用abstract修饰
2. 接口中定义的所有方法都必须是公有
3. 要实现一个接口,必须使用implements操作符类中必须实现接口中定义的所有方法
4. 一个类可以实现多个接口,实现多个接口时,接口中的方法名不能重复
5. 接口与接口之间可以继承,使用extends
6. 接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
interface Boss
{
public function fun1();
public function fun2();
public function fun3();
}
interface Message
{
public function fun4();
public function fun5();
public function fun6();
}
abstract class Engineer implements Boss,Message
{
//实现抽象方法1
public function fun1()
{
}
//实现抽象方法2
public function fun2()
{
}
public function fun3();
public function fun4();
public function fun5();
//实现抽象方法6
public function fun6()
{
}
}
class Programmer extends Engineer
{
public function fun3(){};
public function fun4(){};
public function fun5(){};
}
(十六):常见的魔术方法
__construct() | 构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作 |
---|---|
__destruct() | 析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行 |
__set() | 在给不可访问属性赋值时,__set() 会被调用 |
__get() | 读取不可访问属性的值时,__get() 会被调用 |
__call() | 在对象中调用一个不可访问方法时,__call() 会被调用 |
__callStatic() | 用静态方式中调用一个不可访问方法时,__callStatic() 会被调用 |
__isset() | 当对不可访问属性调用 isset() 或 empty() 时,__isset()会被调用 |
__unset() | 当对不可访问属性调用 unset() 时,__unset()会被调用 |
__sleep() | serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组 |
__wakeup() | unserialize() 会检查是否存在一个 __wakeup()方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。 __wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作 |
__clone() | 对象复制可以通过 clone 关键字来完成,这将调用对象的 __clone() 方法 |
__toString() | __toString() 方法用于一个类被当成字符串时应怎样回应 |