PHP 面向对象详解

时间:2021-10-29 16:17:32

对象的主要三个特性 
对象的行为:可以对 对象施加那些操作,开灯,关灯就是行为。 
对象的形态:当施加那些方法是对象如何响应,颜色,尺寸,外型。 
对象的表示:对象的表示就相当于身份证,具体区分在相同的行为与状态下有什么不同。 

面向对象模型 

面向对象的概念: 
oop(面向对象的编程)它能是其代码更加简洁易于维护并且具有更强的可重性 

什么是类: 
类是具有相同属性和服务的一组对象的集合比如说人,书,轮船,车都属于类,他为属于该类的对象做了一个统一的抽象描述,在编程的语言中类是一个单独的程序,它应该有一个类名包括属性的说明和服务两个部分。 
什么是对象: 
对象是系统中描述客观事件的一个实体,他是构成系统的一个基本单位。*数据与代码都被捆绑在一个实体当中*,一个对象由一组属性和对这组属性进行操作的一组行为组成。 
从抽象的角度来说,对象是问题域或实现域中某些事物的一个抽象。他反映该事物在系统中保存的信息和发挥的作用:它是一组属性和有权对这些属性进行操作的一个封装体。客观世界是由对象和对象之间的联系组成的。 
类和对象的关系: 
类与对象的关系就如模具和铸件的关系,类的实力化的结果就是对象,而对对象的抽象就是类,类描述了一组有相同特性(属性)和相同行为的对象。 

类与属性和方法 

PHP中定义类语法格式: 

复制代码代码如下:


class classname [可选属性]{ 
public $property [=value];… //用public声明一个公共标识 然后给予一个变量 变量也可以赋值 
function functionname ( args ){ //类的方法里的成员函数 
代码} … 
//类的方法(成员函数) 


生成对象(类的实例化): $对象名=new classname( );

使用对象的属性 

在一个类中,可以访问一个特殊指针$this当在该类中通过一个操作设置或访问该变量时,使用$this->name来引用. 
对象的生成 
定义好类后用一个new来声明,由于对象资料的封装特性,对象是无法由主程序区块直接访问的须通过对象来调用类中所定义的属性和行为函数,间接地达成存取控制类中资料的目的。 
对象和类的关系 
对象和类的关系: 
对象是实际存在的,占有动态资源。 
类是对象的蓝图,可能占有静态资源。 
对象属性占有动态资源 
类(静态)属性实际上是有类名字空间上的"全局变量" 
性能考虑: 
每个对象要单独占用数据空间 
增加的调用层次可能消耗执行时间 
方法的参数形式和传递方式 
方法的参数可以是基本数据类型、数组和类对象。 
基本数据类型:值参传递 
数组:值参传递 
类对象:引用传递 
构造函数 
构造函数是在类中起到初始化的作用 
构造函数的生成方法与其他函数一样只是其名称必须是__construct(). 
语法格式: 
function __construct(参数){ 
。。。。。。。。 

范例: 

复制代码代码如下:


class Person{ 
public $name; 
public $sex; 
public $age; 
function __construct($name,$sex,$age){ 
echo "我是构造函数<br>"; 
$this->name=$name; 
$this->sex=$sex; 
$this->age=$age; 


输出结果:初始化 

析构函数 

当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。应在退出前在析构函数中用释放内存。 
析构函数__destruct 析构函数没有任何参数 
范例: 

复制代码代码如下:


class person{ 
function _ _destruct( ) 
{ echo "bye bye !"; } 

$a=new person(); 


访问类型 
public 公共的(公共修饰符) 类内部与类外部都可以访问的 
private 私有的(私有修饰符) 只能在类内部访问 
protected 受保护的(保护成员修饰符) 子类可以访问 类外部不可以访问 

oop的三个重要特性 

封装,继承,多态 
封装性:封装性就是把对象的属性和行为结合成一个独立的单位。 
封装一个类需要两步 第一步是私有化一个类 第二步是用set和get 做出读取赋值的操作 
他的好处是:隐藏类的实现细节,可以方便加入逻辑控制性,限制对属性的不合理操作,便于修改增强代码的可维护性。 

__get与__set 
一般说把类私有话更符合现实的逻辑。 
预定义两种函数来进行获取与敷值操作。 
__get 获取值通常是域的值 
__set 设置值通常是域的值 
__call 调用一个对象中不存在的方法时,就会产生错误call()这个方法来处理这种情况。 

静态属性和方法 

static关键字 来声明静态方法 
static静态变量 在类的内部生成一个静态变量 就是能够被所有类的实力化共想 也就是说静态成员则放到了"初始化静态段",在类第一次被加载的时候放入的,可以让堆内存里面的每个对象所共享 
使用方法:self::$静态属性、self::静态方法 
static function p(){ 
echo self::$country; 
echo self::PI;//访问常量 
//echo $this->name;在静态方法中只能操作静态属性 
//self::p(); 

外部调用:类::$静态属性、类::静态方法 

const关键字:用来生成常量 常量是唯一的不能改变的 惯例常量为大写 
const CONSTANT = 'constant value'; 生成一个常量 
echo self::CONSTANT;//类内部访问 
echo ClassName::CONSTANT;//类外部访问 

继承性 

B类的对象拥有A类的全部属性与行为,称作B对A类的继承。 
假如一个类从多个类中继承了属性与服务,这称为多继承,通常我们成为继承类为子类被继承类为父类,在PHP中只有单继承,但一个父类可以被多个类继承,但是一个子类只能有一个父类,但是允许关联继承,通过继承可以减化类的定义。 
extende声明继承关系 
语法格式:class B extends A 此范例指明 B继承了A 
类的外部访问对子类是有效的 
子类与父类的属性与方法 
子类继承父类的所有内容,但父类中的private部分不能直接访问 
子类中新增加的属性和方法是对父类的扩展 
子类中定义的与父类同名的属性是对父类属性的覆盖,同名的方法也是对父类方法的覆盖 

重写的方法 

在子类中,使用parent访问父类中的被覆盖的属性和方法 

parent::__construce(); 
parent::$name; 
parent::fun(); 

覆盖父类原有属性 
clone克窿对象 语法格式$c=clone $p; $c克窿的对象$p 输出echo $c->name; 

对象比较 
===两个比较运算符。 
==是比较两个对象的内容。 
===是比较对象的句柄,即引用地址。 

instanceof操作符用于检测对象实力是否属于某一个类的类型 属于返回true 不属于返回false 
__clone()如果想在克隆后改变原对象的内容,需要在__clone()中重写原本的属性和方法 
function __clone(){ 
$this->name="我是一个克隆人"; 


final表示一个类是最终版本 也就是说它不能在被子类调用 

多态性 

多态性是指在父类中定义的属性或行为被子类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在父类及其各个子类中具有不同的语义。 
就是说同一种方法在子类与父类中执行的结果不同。 

复制代码代码如下:


class A { 
function info(){ 
echo "A INFO"; 


class B extends A { 
function info(){ 
echo "B INFO"; 


class C extends A { 
function info(){ 
echo "C INFO"; 


function printinfo($obj){ 
function printinfo(A $obj){ 
if($obj instanceof A) 
$obj->info(); 
$obj->info(); 


$a=new A(); $b=new B(); $c=new C(); 
printinfo($a); //输出A INFO 
printinfo($b); //输出B INFO 
printinfo($c); //输出C INFO 



抽象方法和抽象类 

抽象方法是作为子类摸版使用的。 

复制代码代码如下:


abstract class Person{ 
public $name; 
abstract function getInfo(); 


抽象类不能被实力话,一个抽象类中,必须有一个抽象方法。但是抽象类中可以定义动态函数。 
接口 
当一个类继承了一个接口之后,它要覆盖接口的所有方法,接口只能声明常量,接口的方法必须定义为共有否则无法继承,接口可以与多个接口间继承 
语法: 

复制代码代码如下:


interface PCI{ 
const TYPE="PCI"; 
//public $name; error 
function start(); 
function stop(); 


接口中的方法可以声明为static 

复制代码代码如下:


interface A{ function a();} 
interface B{ function b();} 
interface C extends A{ function c();} 
class D implements B,C{ 
function a(){} 
function b(){} 
function c(){} 


 
类的声明: 

复制代码代码如下:


<?php 
    权限修饰符 class 类名{ //权限修士符号:public,protected,private 或者省略3者. 
      //类体;        //class 是建类关键字 
    }             //类名必须跟在class 后面,且跟上{}.{}之间放类的成员. 
  ?> 
//ps:在class关键字前可以加权限修饰符外,还可以加static,abstract等关键字.一个类,即一对大括号之间的全部内容都要在一段代码段中,不允许将类中的内容分割成对块. 
<?php 
  class ConnDB{ 
    //.... 
?> 
<? 
    //... 
  }; 
?> 


成员属性: 
  在类中直接声明的变量称为成员属性/变量.其类型可以为php中的标量类型和复合类型,使用资源类型和空类型是无效的. 
此外,成员属性的声明时,必须要有关键字来修饰:有特定意义的关键字:public,protected,private ;不需要特定意义:var.声明成员属性时,没有必要赋初始值. 

成员常量: 

  以const常量修饰,例如:const PI = 3.1415926; 
  常量的输出不需要实例化,直接由类名+常量名调用即可,格式为: 类名::常量名 
ps. 特殊的访问方法:--------"$this" 和 "::" 
1) $"this" 存在于每个成员方法当中,它是一个特殊的对象以用方法.成员方法属于那个对象,$this应用就代表那个对象,其作用就是专门完成对象内部成员之间的访问. 
2) "::"成为作用域操作符,使用这个操作符可以在不创建对象的情况下调用类中的常量,变量和方法. 其语法格式如下: 

  关键字::变量名/常量名/方法名 

  关键字:parent,可以调用父类成员中的成员变量,成员方法和常量; 
      self,可以调用当前类中的静态成员和常量; 
      类名,可以调用类中的常量,变量和方法;    
   
成员方法: 

  在类中声明的函数成为成员方法,在一个类中可以声明多个函数,即对象可以拥有多个成员方法.成员方法的声明和函数的声明相同,唯一特殊之处就是成员方法可以有关键字对它进行修饰,从而控制其访问权限. 
类的实例化 

  创建对象:

    $变量名 = new 类名称([参数]); //类的实例化. 
  访问类成员: 
    $变量名 -> 成员属性 = 值; 
构造方法和析构方法 
构造方法是对象创建完成后第一个呗对象自动调用的方法.它存在每个类的声明当中,是一个特殊的成员方法,一般用来完成一些初始化操作.如果类中没有构造方法,系统会默认自动生成一个没有参数的构造方法. 
  格式: 

复制代码代码如下:


function _construct(形参列表){ 
      //方法体 
    }; 


析构方法则如构造方法相反,它是在对象被销毁前最后一个调用的方法.它将完成一个特定的操作,如关闭文件和释放内存. 
  格式: 

复制代码代码如下:


function _destruct(){ 
      //方法体  
    }; 


面向对象特点:封装性,抽象性,多态性. 
封装: 
  将类中的成员属性和方法结合成一个独立的相同单位,并且尽可能的隐藏对象的内容细节.其目的是确保类以外的部分不能随意存取类的内部数据(成员属性和成员方法),从而避免外部错误对内部数据的影响. 
  类的封装是通过关键字public,private,protected,static和final实现的.各关键字的作用请查看php相关文档. 
继承性: 
  使一个类继承并拥有另一个已存在的类的成员属性和成员方法,其中被继承的类成为父类,继承的类成为子类.通过继承能够提高代码的重用性和可维护性.类的继承用 extends 关键字. 
  格式: 

复制代码代码如下:


class 子类名称 extends 父类名称{ 
      //子类方法体. 
    } 


通过parent::关键字也可以在子类方法中调用父类的成员方法,格式如下: 
  parent::父类的成员方法(参数); 

覆盖父类的方法: 

  所谓的覆盖父类的方法,也就是使用子类中的方法替换从父类中继承的方法,也叫方法的重写.重写的关键就在与子类中创建与父类中相同的方法,g包括方法名称,参数和返回类型. 

多态性: 
  多态性是指一段程序能够处理多种类型对象的能力.php多态有两种实现方法,即通过继承实现多态和通过接口实现多态. 
通过继承实现多态,即通过重写继承的成员方法来达到多态的效果. 

复制代码代码如下:



<?php 
abstract class ParentClass{ 
abstract function printMessage(); 

class SubClassA extends ParentClass{ 
function printMessage(){ 
echo "i am message from class A"; 


class SubClassB extends ParentClass{ 
function printMessage(){ 
echo "i am message from class B"; 


function printMSG($object){ 
if( $object instanceof ParentClass){ 
$object->printMessage(); 
}else{ 
echo "error!"; 


$objectA=new SubClassA(); 
printMSG($objectA); 
$objectB=new SubClassB(); 
printMSG($objectB); 
?> 


通过接口实现多态,通过定义接口,与空方法.然后类继承接口. 

复制代码代码如下:



<?php 
interface interfaceInfo{ 
function printMessage(); 

class ClassA implements interfaceInfo{ 
function printMessage(){ 
echo "message form class A"; 


class ClassB implements interfaceInfo{ 
function printMessage(){ 
echo "message form class B"; 


function printMSG($object){ 
if($object instanceof interfaceInfo){ 
$object -> printMessage(); 
}else{ 
echo "error !"; 


$objectA =new ClassA(); 
printMSG($objectA); 
$objectB =new ClassB(); 
printMSG($objectB); 
?> 


ps. 抽象类和接口. 
抽象类和接口都是不能被实例化的特殊类.他们都是能够配合面向对象多态性一起使用. 
抽象类: 
  抽象类是一种不能实例化的类,只能作为其他类的父类来使用.抽象类使用abstract 关键字来声明,其格式如下: 

复制代码代码如下:


abstract class 抽象类名{ 
      abstract function 成员方法(参数);// 
    } 


抽象类和普通类相似,包含成员变量,成员方法.两者区别在于抽象类至少要包含一个抽象方法.抽象方法没有方法体,其功能的实现只能在子类中完成.抽象方法也使用关键字 abstract 来修饰. 

接口: 
  继承特性简化了对象和类的创建,增强了代码的可重用性.但php只支持单继承,如果想实现多重继承,就要使用接口. 
接口的声明:通过interface 关键字来实现,接口中声明的方法必须是抽象方法,接口中不能声明变量,只能使用const 关键字声明为常量的成员属性,并且接口中所有成员都必须具备puclic 的访问权限.ainterface 声明接口格式如下: 

复制代码代码如下:


inerface 接口名称{ 
   //常量成员;//成员只能是常量. 
   //抽象方法; 
  } 


由于接口不能实现实例化操作,因此只能借助子类继承接口的形式来实现.实现的格式是: 

复制代码代码如下:


Class 子类名 implements 接口名1[,接口名2,接口名3,.....]{ 
  //子类方法体. 


常用关键字: 
  1) final:final之意为最终的,最后的.这就以为着通过final 关键字修饰的类和方法都为最终版本.不能被继承,也不能有子类.不能重写,也不能被覆盖. 
  2) static: 通过static 关键字修饰的成员属性和成员方法称为静态属性和静态方法.静态成员属性和方法不需要被实例化就能直接使用. 
   静态属性:它属于类本身,而不属于类的任何实例.它相当于存储在类中的全局变量,可以在任何位置通过类来访问.访问格式为: 
      类名称::$静态属性名称; 
      如果你要在类内部的成员方法中访问静态属性,那么在静态属性的名称前加上操作符: "self::" 即可. 
   静态方法:由于其不受任何对象限制,因此可以不通过类的实例化而直接引用类中的静态方法.引用格式如下: 
      类名称::静态方法名(参数); 
      如果你要在类内部的成员方法中调用静态方法,那么在静态方法的名称前加上操作符: "self::" 即可.在静态方法中只能调用静态变量,而不能调用普通变量;而普通方法中则可以调用静态变量. 
使用静态成员除了不需要实例化外,另一个作用是在对象被销毁后,仍然保留呗修改的静态数据,以便下次调用. 
  3) clone.对象的克隆可以通过关键字来实现.使用clone对象与原对象没有任何关系,即克隆对象会重新申请一份存储空间来存放原对象内容.格式如下: 
      $克隆对象 = clone $原克隆对象名称; 
    克隆成功后,他们的n成员方法,属性以及值完全相等.如果要对副本重新初始化,就要用到 _clone(). 
     魔术方法_clone()可以对克隆后的副本对象重新初始化.它不需要任何参数,其中自动包含$this (副本对象)和 $that (原对象) 对象的引用. 
对象的比较: 
  "==" 表示比较两个对象的内容,"==="表示比较两个对象的引用地址相等. 
对象类型的检测: instanceof 操作符可以检测当前对象属于那个对象. 

面向对象---常用魔术方法: 
以上我们已经了解的常用魔术方法有:_construct(),_destruct(),_clone.下面我们再接着介绍几个常用魔术方法. 
_get(),_set(); 
  以上两个方法用于对私有成员精细复制或者获取值的操作. 
  _set()在程序运行中为私有的成员属性设置值,它不需要任何返回值._set()方法包括两个不可省略的参数:变量名和变量值.这个方法不需要主动调用,可在方法钱加上prive关键字. 
  _get():在程序运行中,在对象的外部获取私有成员的属性的值.他有一个参数:私有成员属性名称.他返回一个允许对象在外部使用的值.此方法同样不许主动调用. 

_isset(),_unset(): 
  isset()函数用于检测变量是否存在.而在面向对象中可以通过isset()函数对公有的成员属性进行检测,但对私有成员属性,此函数则不起作用.因此,_isset()函数正是为了起到此作用而创建.格式如下: 
  bool _isset(string name); 
  _unset()则同样为了删除制定的变量和对象的私有成员属性.格式如下: 
  void _unset(string name);// 
_call(): 
  _call()方法的作用是当程序试图调用不存在或不可见的成员方法时,php会先调用_call()方法来存储方法名及其参数(方法名和方法参数).其中方法参数是以数组的形式存在. 
_toString()方法: 
  其作用是当使用echo 或者print输出对象时,将对象转化为字符串. 
  如果没有_toString()方法,直接输出对象时将会发生致命错误. 
  输出对象时应注意的是,echo 或print 语句后面直接跟要输出的对象,中间不要加多余的字符,否则_toSting()将不会被执行. 
_autoload()方法: 
  将一个独立的,完整的类保存到一个php页中,并且文件名和类名保持一致,这是每个开发人员都需要养成的良好习惯.这样下次在使用的时候就能够轻松的找到它.但有一种情况:如果要在一个页面中引进很多的类,就需要使用include_once()函数或者require_once()函数一个个地引入.php5中引入_autoload()方法可以自动实例化需要使用的类.当一个类还没实例化时,_autoload()会自动到指定的路径下面自动查找和类名相同的文件.找到则继续执行,否则报错. 

复制代码代码如下:



<?php 
  function _autoload($class_name){ 
    $class_path = $class_name.'.class.php'; 
    if(file_exists($class_path)){ 
      include_once($class_path); 
    }else{ 
      echo '类不存在或者类路径错误'; 
    } 

  $class = new Class(); //将会自动加载. 
  echo $class; //输出类内容.如自定义了_toString()方法;则会输出_toString()中定义的内容. 
?>