[TOC]
面向对象
1. 面向对象的基本概念
1.1 什么是面向对象编程。
准确的说面向对象编程我们叫 OOP.面向对象的编程分为三部分:面向对象分析(Object Oriented Analysis,OOA)、面向对象设计(Object Oriented Design,OOD),以及面向对象编程(Object Oriented Programming)。面向对象编程的两个中个重要的概念是类和对象。
1.2. 类
世间万物皆对象,万事万物皆对象。当然,这是在 js 当中的一个概念。在其他的编程语言当中,我们说时间万物都具有它自身的属性和方法,通过这些属性和方法,可以将不同的事物区分开来,这就是我们在座的面向对象类的抽象。例如,人具有身高。体重和肤色等等这些属性。还可以吃饭,学习走路可以做一些活动。这些活动就是人具有的功能。而前面所说的体重,肤色,身高等等这些是什么呢?是属性。所以我们就可以把人看作是程序当中的一个类。那么人的身高可以看做什么?可以看做类的属性走路啊,吃饭呀,可以看做类的方法。所以什么是类,类是属性和方法的集合.是面向对象编程最核心的东西。也是它的基础。所以通过类呢,我们可以将一些零散的用来去实现某一个功能的代码进行一些管理。比如说,我们可以创建一个运动类。爱运动类里面包括有这么些个属性姓名身高体重年龄。和性别,然后我再定义几个方法,他能踢足球,他能打篮球啊,能举重能跳高。能吃能玩。
1.3. 对象
类只是具备某项功能。一个抽象模型实际应用当中呢,我们需要使用的是对象。所以我们就需要从那当中去实例化出来这个对象,然后去使用这些对象。对象呢,是类进行实例化之后的一个产物。它是一个实体,是一个独立的个体。例如,我们仍然以人为例。"黄种人是人"这句话里边儿。没有错误对吧,但是反过来说 "人是黄种人",就有问题,因为除了黄种人,还有白人,黑人等就,这里的"黄种人"就是"人"这个类中的一个实例对象。
1.4. 面向对象的三大特征
面向对象编程的大大特征就是封装性,继承性,多态性
1.4.1. 封装性
封装性也可称之为信息隐藏,就是把一个类的使用和实现分开,只保留有限的接口(方法)与外部练习。同时也避免程序之间的 相互依赖而产生的不便。
1.4.2. 继承性
继承性就是派生类(子类)自动继承一个或多个基类(父类)中的属性与方法。并且我们可以重写和添加新的属性方法。可以简化对象和类的创建,提高代码的可复用性,继承分单继承和多继承。PHP 中支持的是单继承。一个子类有且只有一个父类。
1.4.3. 多态性
同一个类的不同对象,调用一个方法可以获得不同的结果。增强程序的灵活性和重用性。
2. PHP 对象
2.1. 类的定义
和很多其他面向对象的语言一样,PHP 通过 class 关键字加类名来定义类。
<?php
class SportObject{
// ----
}
?>
2.2. 成员方法
类中的函数被称为成员方法,函数与成员方法唯一的区别就是函数实现的是某个独立的功能。而成员方法实现的是类的一个行为,它是类的其中一部分。
关键字(修饰符) 成员方法
<?php
class SportObject{
function bealBasketBall($name,$age,$height,$sex){
echo $name.'<br>';
echo $age.'<br>';
echo $height.'<br>';
// return ;
}
}
?>
2.3. 类的实例化
首先我们要实例化对象(通过 new 关键字 实例化对象),才能通过对象执行对应的行为方法。通过对象->成员方法 来调用成员方法。
<?php
class SportObject{
function bealBasketBall($name,$age,$height,$sex){
if($height>=180){
return $name.'符合打篮球的身体素质要求!';
}else{
return $name.'不符合打篮球的身体素质要求!';
}
}
}
$s1=new SportObject();
echo $s1->bealBasketBall('曾辉',20,170,'男');
$s2=new SportObject();
echo $s1->bealBasketBall('曾辉2号',40,181,'男');
?>
2.4. 成员变量
类中的变量,也称为成员变量。有些人也把它叫做属性或者字段。成员变量的是用来保存数据信息。或者与成员方法进行一些交互来实现某项功能。
定义成员变量和成员方法:
关键字(修饰符) 成员变量名
关键字可以使用public ,private, protected, static 中的任意一个。
访问成员变量和成员方法的方法一样,对象->成员变量
class SportObject{
// 声明成员变量。
public $name;
public $height;
public $sex;
public function boolFootBall($name,$height,$sex){
return $name.'是个足球运动员';
}
}
$s1=new SportObject;
$s1->name='佚名';
var_dump($s1);
// $s1->boolFootBall('佚名');
<table> <tr><td bgColor="orange"><strong>注: this->" 还是"对象名->"哪种格式,后面的变量名是没有$符号的.
</strong></td></tr></table>
2.5. 类常量
常量是在程序运行期间,不可改变的量,我们说他是一个恒值,举例圆周率就是一个常量。定义常量,我们使用关键字 const。
class SportObject{
const SPORT_TYPE="体育运动";
public $name;
function setName($name){
$this->name=$name;
}
function getName(){
return $this->name;
}
}
$s1=new SportObject;
$s1->setName('aaa');
echo $s1->getName().'<br>';
echo $s1->name.'<br>';
echo SportObject::SPORT_TYPE.'通过类::常量名';
2.6 构造函数和析构函数
2.6.1 构造函数
当一个类实例化为一个对象的时候,可能可能会随着对象的初始化而初始化一些成员变量。就是给一些成员变量复制值。这种情况下我们就可以使用构造函数。因为咱对象实例化过程当中构造函数是自动执行的。
class Person{
public $name;
public $age;
public $sex;
public $height;
// 我们可以通过"__construct()"
public function __construct(){
echo '123';
}
}
$p1=new Person;
// 如果成员变量过多,写起来比较麻烦
// $p1->name='aa';
构造函数是在初始化对象时使用的,如果类中没有构造方法,PHP 会自动生成一个构造函数,自动生成的构造方法是没有参数的。
2.6.2 析构函数
析构函数的作用和构造方法方法刚好相反,是对象被销毁时被调用的,作用呢是释放内存。
<?php
class Person{
public $name;
public $age;
public $sex;
public $height;
// 我们可以通过"__construct()"
// 构造函数
public function __construct($name,$height,$age,$sex){
// 为成员变量赋值。
$this->name=$name;
$this->height=$height;
$this->age=$age;
$this->sex=$sex;
echo $this->sayHi();
}
public function sayHi(){
return "你好,我叫$this->name ,我今年$this->age 岁了,身高$this->height,性别$this->sex";
}
// 析构函数
public function __destruct(){
echo '已经被释放掉了';
}
}
$p2=new Person("佚名",180,23,'女');
2.7 继承和多态
其实继承和多态啊最根本的作用就是完成代码的重用。
2.7.1 继承
子类继承父类的所有成员变量方法,包括构造方法,当子类被实例化的时候,PHP 会先在子类当中找构造方法,如果子类已经有自己的构造方法。PHP 会先调用子类的方法。当子类当中没有的时候,PHP 才会去调用。父类当中的构造方法,这就是继承。
// 父类(基类)
class SportClass{
// 定义成员变量
public $name;//姓名
public $age;//年龄
public $weight;//体重
public $sex;//性别
public function __construct($name,$age,$weight,$sex){
$this->name=$name;
$this->age=$age;
$this->weight=$weight;
$this->sex=$sex;
}
function sayHi(){
echo '你好,我是'.$this->name;
}
}
/**子类(派生类)BealBasketBall*/
class BealBasketBall extends SportClass{//定义子类,继承父类
// 定义成员变量 身高
public $height;
public function __construct($name,$height){
$this->height=$height;
$this->name=$name;
}
// function sayHi(){
// echo '你好,我是'.$this->name;
// }
}
$b1=new BealBasketBall('曾辉',198);
2.7.2 多态
多态好比有一个成员,方法是让大家去游泳,这时有人带着游泳圈还有人拿着浮板。还有人什么也不带。虽然是同一种方法,但是却产生了不同的形态,这就叫多态。
多态存在两种形式,覆盖和重载。
1).所谓的覆盖,在子类中重写父类的方法。而在子类的对象当中,虽然调用的是父类当中相同的方法,但返回的结果是不一样的。你看啊,上面的那个例子当中都调用了父类当中的说明方法。但是返回的结果却不同。
2).再就是重载,重载是类的多态的另外一种体现。函数在重载的时候会有一个标识符。被当做多个函数名称。而且呢,能够通过函数的参数的个数或者参数的类型,将这些同名的函数区分开来,(方法名称是相同的),可能是参数的数量或者参数的类型不同。以便于去使用和调用的时候不发生混淆。
PHP所提供的重载(overloading)是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
class A{
function __call($name,$num){
echo "方法名称:".$name.'<br>';
echo '参数存在的个数:'.count($num).'<br>';
if(count($num)==1){
echo $this->list1();
}
if(count($num)==2){
echo $this->list2();
}
}
public function list1($a){
return "这是list1函数,:参数:$a";
}
public function list2($a,$b){
return "这是list1函数,:参数1:$a ,参数2:$b ";
}
}
$a=new A;
$a->list(1);
2.8 "$this->" 和"::"的使用
PHP通过为变量"this->**
在本类内部我们可以通过"this->成员变量"||"this->"只在类的内部使用
class Demo{
function exam(){
if(isset($this)){
echo '$this的值:'.get_class($this);
}else{
echo '$this 未定义';
}
}
}
$d1=new Demo;
$d1->exam();
2. 操作符::
$this只能在类的内部去使用。操作符"::"可以在没有声明任何实例的情况下,访问类当中的成员方法或成员变量。
关键字::变量名/常量名/方法名
关键字有三种情况:
- parent: 可以调用父类中的 成员变量,成员方法和常量
- self:可以调用当前类中的 静态成员和常量
- 类名:可以调用本类中的静态变量,常量和静态方法
class A{
const NAME_='A';
public $name;
public $age;
public $sex;
public function __construct($name,$age,$sex){
$this->name=$name;
$this->age=$age;
$this->sex=$sex;
}
}
class B extends A{
const NAME_='B';
public $height;
public $weight;
public function __construct($name,$age,$sex,$height,$weight){
parent::__construct($name,$age,$sex);
$this->height=$height;
$this->weight=$weight;
}
public function a(){
self::NAME_;
parent::NAME_;
}
}
$b1=new B('姓名','年龄','xingbie','身高','体重');
B::NAME_;
2.9 修饰符
public、private、protected、static和final。这些关键字是用来限定类成员(包括方法和变量)的访问权限。
2.9.1 public(公共成员)
顾名思义就是可以公开的,没有必要去隐藏的一些数据信息。可以用public来去修饰当前的成员方法或者成员变量。它可以在程序的任何位置出现(类的内部,类的外部)。可以被其他的类和对象去调用。子类呢可以继承和使用父类当中所有的,公共成员。
class Person{
public $name="李雷";
public function fn(){
// 1.可以在类的内部访问,对当前类的 内部可见
echo $this->name;
}
}
class Students extends Person{
public function fn1(){
// 2.可以在子类的内部访问,对子类的内部可见
echo $this->name;
$this->fn();
}
}
// 3.在类的外部可见
$s1=new Person();
$s1->fn();
$s2=new Students();
$s2->fn();
$s2->fn1();
2.9.2 private(私有成员)
被private关键字所修饰的成员方法和变量,只能在所属类的内部被调用和修改,不可以在类外部访问,在子类中也不可以。
<?php
class Book{
private $name='HTML';
public function setName($name){
// 1.在当前类内部 可访问
$this->name=$name;
}
public function getName(){
echo $this->name;
}
private function c1(){
echo '123';
}
}
class Histoty extends Book{
public function getBookName(){
// 2.在子类内部不可见 不可访问继承来的父类中的私有成员变量 私有方法
echo $this->name;
$this->c1();
}
}
// $b1=new Book;
// $b1->setName('PHP');
// $b1->getName();
// 3.在类的外部不可访问 私有成员变量或私有成员方法
// $b1->name='js';
// $b1->c1();
$h1=new Histoty();
$h1->getBookName();
对于成员方法和成员变量,如果没有指定关键字,那就默认是public。
2.9.3 protected(保护成员)
被protected 修饰的类成员,可以在当前类和子类中被调用。去其他地方则不可以访问。
class Person{
protected $money=10;
public function fn(){
echo $this->money;
// 1.在当前的内部可以访问
}
}
class Stu extends Person{
public function fn1(){
echo $this->money;
// 2. 可以在子类的内部访问
}
}
// 3. 在类的外部不能直接访问,
$p1=new Person;
$p1->fn();
// echo $p1->money;
$s1=new Stu;
$s1->fn1();
2.10 静态成员(变量,方法)
不是所有的方法都要通过创建对象来去调用的,我们可以。通过给变量或者方法加上static关键字来直接调用。也叫做访问静态成员。
关键字::静态成员
关键字可以有两种:
- self,在类的内部调用静态成员是使用。
- 静态成员所在的类名,在类的外部调用类内部的静态成员时所使用。
在静态方法当中只能调用静态变量,而不能调用普通的变量。而普通方法里面可以调用静态变量。
使用静态成员,除了可以不需要实例化对象外,另一个作用就是在对象被销毁后,仍然保留被修改的静态数据,以便于下次继续使用。
class Book{
static $num=0;//声明一个静态变量$num,初始值为0;
public function showMe(){
echo '您是第'.self::$num.'位访客';
self::$num++;//
}
}
$b1=new Book();
$b1->showMe();
$b2=new Book();
$b2->showMe();
echo '一共有'.Book::$num.'位访客';
2.11 final 关键字
被final修饰过的类和方法就是"最终的版本",如果类被final修饰过,该类不可以再被继承,也不能再有子类。
final class Book{
public $name='';
public function __construct($name){
$this->name=$name;
}
}
class Histoty extends Book{
public $height='';
}
//结果: Fatal error: Class Histoty may not inherit from final class (Book)
如果方法被final修饰过,方法在子类中不可以进行重写,也不可能被覆盖。
class Book{
public $name='';
public function __construct($name){
$this->name=$name;
}
final public function getName(){
echo $this->name;
}
}
class Histoty extends Book{
public $height='';
public function getName(){
echo '123';
}
}
//结果:Fatal error: Cannot override final method Book::getName() in
2.12 对象类型检测
instanceof操作符可以检测当前对象是属于哪一个类。
ObjectName instanceof ClassName
class Book{
public $name='';
public function __construct($name='佚名'){
$this->name=$name;
}
}
class History{
}
$a=new Book;
$b=new History;
// var_dump($a instanceof Book);//true
var_dump($b instanceof Book);//false
3.魔术方法(__)
3.1 __get和__set() 方法
这两个魔术方法的作用分别是:
当程序试图去写入一个不存在或者不可见的成员变量的时候PHP就会执行__set()方法。__set()方法呢,包括有两个参数,分别是变量名称和变量的值,这两个参数不可省略。
当程序调用一个未定义或者不可见的成员变量的时候,可以通过__get()方法来去读取变量的值.__get()这个方法有一个参数表示你要调用的这个变量名称。
<?php
class SportClass{
public $height='1231';
private $type='21312';
public function __get($name){
if(isset($this->$name)){//判断变量是否被声明
echo '变量'.$name.'值:'.$this->$name.'<br>';
}else{
echo '变量'.$name.'未定义';
$this->$name=0;
echo $this->$name;
}
}
public function __set($name,$value){
if(isset($this->$name)){
echo '私有成员';
echo '变量'.$name.'赋值:'.$value.'<br>';
}else{
$this->$name=$value;
echo '变量不存在';
}
}
}
$b=new SportClass();
// echo $b->type;
// echo $b->sex;
// $b->type='213';
$b->sex=234;
echo $b->sex;
3.2 __tostring()方法
当使用echo或print输出对象时,将对象转化为字符串。
class SportClass{
private $type='21312';
public function __tostring(){
return $this->type;
}
}
$b=new SportClass;
echo $b;
3.3 __autoload()方法
尝试加载未定义的类是,触发__autoload()方法,__autoload()接受一个参数,参数是类的名称。
function __autoload($classname){
$class_path=lcfirst($classname).'Class.php';
if(file_exists($class_path)){
include_once($class_path);
}
}
$b=new BaseFile;
var_dump($b);
$c=new Base();
var_dump($c);
3.4 中文字符串截取类
在Php当中啊!我们经常要去对字符串进行一些截取。如果是英文字符串的话,我们可以直接使用substr()函数来去完成。但是当出现中文字符串的时候,如果你依然使用这个substr()函数,就有可能会出现乱码的情况。因为一个汉字是由两个字节组成的。所以当截取的字符如果出现奇数的时候,就有可能将一个汉字给拆分开来。从而导致输出一个不完整的汉字,显示出来就是乱码。