当前位置: 首页 > news >正文

php面向对象

面向对象是一种编程思想,对于小白来说,瞬间掌握,难度很大,需要体会和实践,慢慢领悟,为了防止陷入思想的无底洞,先不用管为什么
这么写,前期我们需要先熟悉语法和用法,随着代码量的增多,理解自然会深化.前期一定要先做到以下几点:
1. 类声明语法 试声明student类,有score属性和study方法
2. 权限封装 知道public、 protected、 private各自的可见范围
3. 继承 写A类,再写B类继承自A类,且要重写A类中的某个方法
4. 静态属性与静态方法,知道static静态方法需要用类名::方法名()调用
5. 魔术方法 了解常用魔术方法分别在什么时间被调用
6. 写一个抽象类,并用2个子类分别继承实现 分析这2个子类有什么共同特点?
7. 写一个接口,并用2个类分别继承实现 分析这2个类有什么共同点

面向过程 :每个小系统有着明确的开始和和结束 。开始和结束之间有着严谨的因果关系。

比如 :上帝创造一个人,如果有70亿人那就很麻烦

随机函数先获取随机的数字 作为数组的下标,然后再从数组中获取对应下标的数字。

 

面向对象

引入例子 :女娲 人身蛇尾 , 用女娲造人引出类和实例 : 女娲造人前先 思考 人的形象 然后再造人

所以 :人的形象是抽象的,用来说明人的特点;而每一个人都是具体的,且符合人的形象

 

类 :所有对象共同点的一个抽象!(就是一个 制造说明书)

对象 :就是根据说明书制造出来的具体对象

类中有什么? 属性(比如人:身高,体重,姓名)

能干什么?功能(说活,吃饭)

用 变量 和 函数 分别模拟 属性 和 功能

面向对象中 ,方法即是函数 ; 属性即是变量 ,只是面相对象中一般说方法和属性

 

new 类名();//直接产生一个对象并返回该对象

$a = new 类名(); //那么a对象就包含 类中声明的所有属性(类似关联数组)

  

要调用对应的属性值可以 $a -> name (name不用$);要调用对应的方法 $a -> say()

面向对象oo(object oriented)oop加编程

声明类的时候 :

内存分配给类一个空间,,里面存放着类定义的属性和函数

new对象的时候 :

1、 申请内存,生成对象(属性集合)

2、 如果有构造函执行

3、 返回对象的地址

 

                       内存分配图

 

语法就是法律; 规范 就是 道德

(1)属性的初始化 不能是表达式 如 : $a = 1+3 ;  java中是允许的

(2)同一个域内(比如一个类中),函数不能重复定义(即是名字不能一样)

(3)在一个类里面,如果要调用系统同名的自定义函数,需要用$this,否则调用系统函数 ; 此外一个类里面 一个函数调用 不是他内部的变量或者它调用其他函数也要加 $this

 

构造函数 : __construct() , 注意前面是两个下划线 ; 当new对象(产生对象),调用 ; 构造函数不能被重载即是不能再有同名的

 

析构函数 :__destruct()在对象被销毁的时候调用的函数 。 

如何销毁对象 :

1、显式销毁,unset(),直接赋值为null或者其他值

2、执行完最后一行代码时自动销毁(如果之前已经销毁,则不再销毁)

 

 

对变量指向销毁问题

$a = new People(); //创建一个对象(new People()),并把使用权给变量$a($a是一个变量名,指向这个对象)

$a = $b = $c ;  //3个变量都指向内存中的同一个对象

unset($a);//unset,即是销毁对象(object),但有其他变量$b等仍然指向对象,那么该对象将不能被销毁,但是$a为null不再指向这个对象

 

this绑定

当一个对象调用一个它对应类的方法时,该方法执行之前先完成一个绑定,即是用

$this绑定到调用此方法的对象(这样才能在方法内对这个对象的属性进行操纵),因为方法内如果想访问调用者(即是对象)的属性必须用$this;否则则理解为方法内部的一个局部变量

 

Java中不一样,函数不需要this也能访问方法外的变量

 

封装

封装的概念 : 通过修饰符 改变属性或者函数的访问权限 ,达到保护的作用。

光是封装起来是没意义的,还要供外部交互才行;所以通过一个开放的接口(即是一个函数)供外部操纵;内部的操作,不需要外部知道,从而隐藏内部的一些细节 。

如: 洗衣机,你只要点击启动程序的按钮就能洗衣服,不需要知道洗衣机内部怎么运行

权限修饰符 :private protected public

private修饰的属性只能在其 类里面 才能被访问到。

protected 本类和子类能访问

private访问权限的bug : 对象之间能够相互操作同一个类中的属性,导致一个对象能够修改另一个对象的属性。

 

fatal error(致命错误)

 

封装 操作数据库的 类

类似把某个功能的一段代码放在一个类中 ; 类里面的方法相互调用

用面向对象的思想 对数据库操作 (mysql封装类)

比如把连接数据的操作封装到一个连接函数中

连接数据库

发送 查询

对于select语句 返回查询数据数据

关闭mysql连接

 

继承

子类继承父类的属性和方法,再进一步拓展自己的属性和方法;父类的属性 和方法一般是一个归纳(所有对象都有的),提高代码的重新性

 

拥有问题 :子类继承父类,子类有父类所有的属性和方法,在子类里面能够操作父类中非private修饰的属性或者方法,但是父类中对于private修饰的属性或者方法子类无法操作(类外的范围限制)

  

 

调用与覆盖问题 : 子类里面调用对应的属性时,子类没有覆盖父类中的属性或者方法,则调用父类中的属性或方法,否则只调用子类中的,无论传参数是否对。private的调用除外

 

注意继承父类之后,子类再声明与父类一样的属性,权限符只能越来越宽松或者一样 。 如果父类的属性有static,子类也必须有才能声明

 

★类内一般声明只属性和方法,实例化或者输出等语句要写在方法里或者类外,否则报错

如果子类有和父类一样的方法,能使用parent::方法名()指定调用父类的

 

 

构造函数是可以被继承的;如果子类中没有写构造函数,在实例化子类的时候就会调用父类的构造方法。如果子类重新写则覆盖且只调用子类的。

因此如果父类的构造函数是必须要调用,最好使用parent::__construct()调用一下(java不同,它会先调用父构造再调用子构造;php调用子构造)

比如 :数据库类中 父类构造函数有连接数据库,如果子类写了其他的话构造函数,则连接失败 (Java不同,父子都调用)

 

在类外对象名只能调用类中public修饰的属性,其他的属性可以通过方法来调用。一般不写则默认为public

 

 

多态

只抽象声明父类,具体的工作由子类对象完成

java出现多态是因为它是强类型语言(即是定义了类型不能随便改变),声明的类型 后 传送参数必须是该类型 。 声明参数时,声明为父类型,传参时,能够传子类型。以达到多态的效果。比如:

多颜色手电筒问题 :声明手电筒,并接受玻璃的参数。然后玻璃有多种颜色,以达到不同效果。则为多态

php是弱类型语言,本身没有对类型没有检测,因此简直变态,后来5.3以后,引入了对于对象类型的参数检测。限制了灵活性达到多态

  

 

static 静态属性

一般当 某个属性或者方法 是所有对象固有的(即是不改变),则声明为静态属性,节省内存,随时类名调用;无论函数调用多少次,只初始化第一次.,如 static $a = 1;

静态属性存在于类内存中,而不是对象的内存中。只要有类就能访问到,因此一个静态属性只有一个,改1全变;只能 类名::属性名 访问

 

 

静态方法

普通方法和静态方法都存在 类内存 中 且只有一个

但是静态方法用类名调用,不用this绑定;普通方法需要有对象才能用this绑定调用

 

安装ecshop的时候出现strict standard错误提示,原因是版本高,代码书写语法有误,静态方法调用非静态方法时出现问题。

 

非静态方法,是不能由类名静态调用的.但是 PHP中的面向对象检测的并不严格,

只要该方法没有$this,就会转化静态方法来调用. 

但是,在PHP5.3的strict级别下,或者PHP5.4的默认级别

都已经对类名::非静态方法做了提示

则会提示:Strict Standards: Non-static method Human::eat() should not be called statically 

不能静态的去调用非静态方法 ; 有static修饰的变量和函数不能出现$this

 

isset($this) 这个时候判断有没对象进行绑定;

代码分析

  

 

this就是指向当前对象实例的指针,不指向任何其他对象或类

self, parent的用法  (::(域运算符号))

self:指向类本身,也就是self是不指向任何已经实例化的对象 ,self使用来指向类中的静态属性或者方法

self::$staticProperty

self::staticMothed;

 

parent: 指向父类的指针,一般我们使用parent来调用父类的构造函数。

 

在引入自身的静态属性/静态方法,以及父类的方法时,可以用到.

parent::$staticProperty

parent::Mothed;

 

 

 

★应该选择this还是parent

  

总结使用 

1: 修饰类的属性与方法为静态属性,静态方法

2: static::method(), 延迟绑定

3: 在函数/方法中,声明静态变量用

 

 

单例模式

 

避免多人开发过程,实例化过多导致资源浪费, 限制只实例化一次的模式

 

构造方法不能执行则实例化失败

 

思路 :

 

1、 保护或私有构造函数,房子外部实例化

 

2、 内部开发一个公共的静态方法,负责实例化

 

3、 类有一个静态属性存放对象

 

复制代码
<?php
class Single {
    //设置私有,保存实例状态
    static protected $ins = NULL; //设置为私有,限制类外实例化,若没有子类可去掉final final protected function __construct() { echo '实例化成功!'; } //设置为静态方法,类外能调用,实例化 static public function getinstance() { //self代表当前类,判断是否实例化 if (self::$ins instanceof self) { return self::$ins; } self::$ins = new self(); return self::$ins; } }
$s1 = Single::getinstance(); $s2 = Single::getinstance();
//子类继承父类若还要单例,要用final修饰父类构造方法, //阻止子类重写构造方法自己去new的问题 class Single2 extends Single { }
$s11 = Single2::getInstance(); $s12 = Single2::getInstance();
if ($s11 === $s12) { echo "相等"; } ?>
复制代码

 

 

 

final

 

final 不能修饰属性

 

final 修饰方法,此方法能继承,不能被重写

 

final 修饰类,则此类 不能够被继承

 

 

 

魔术方法

 

是指某些情况下,会自动调用的方法,称为魔术方法 ; 感觉一般都是那些权限不允许调用或者是不存在的属性 才会触发魔术方法

 

PHP面向对象中,提供了这几个魔术方法,

 

他们的特点 都是以双下划线__开头的

 

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state() 和 __clone()

 

__clone()   :克隆方法,当对象被克隆时,将会自动调用

 

 

 

 

 

 

__get() :当我们调用一个权限上不允许调用的属性,和不存在的属性时,__get魔术方法会自动调用,并且自动传参,参数值是属性名。酱紫就能避免系统会直接报错,甚至fatal error,通过__get()我们就能自定义用户访问时的处理行为。注意如果是数组形式的话那么这里的$p相当于键值(即是下标)

 

 

流程:

 

$lily->age--无权-->__get(age);

 

$lily->friend--没有此属性-->__get('friend');

 

 

 

__set() :当为无权操作的属性赋值时,或不存在的属性赋值时,__set()自动调用,且自动传2个参数 属性 属性值

 

 

 

 

 

__isset() :当用isset()判断对象不可见的属性时(protected/private/不存在的属性)

 

会引发 __isset()来执行

 

 

 

isset($obj->xyz) 属性为真,能说明  类声明了一个xyz属性吗?

 

答:不能,因为isset($hua->tail)----没有tail属性---->__isset('tail');-à 如果__isset返回1则不能

 

 

 

__unset() : 当 用unset 销毁对象的不可见属性时,会引发 __unset();

 

 

 

__call($a,$b) : 调用不可见(不存在或无权限)的方法时,自动调用;前参数是方法名,后是传参

 

 

 

__callStatic($a,$b) : 是调用不可见的静态方法时,自动调用.

 

 

 

 

 

__call是调用不可见(不存在或无权限)的方法时,自动调用

 

$lisi->say(1,2,3);-----没有say()方法----> __call('say',array(1,2,3))运行

 

 

 

 

 

__autoload() : 如果调用某个不存在的类,在报错之前,系统会调用__autoload($n)函数,并把"类名"自动传给__autoload函数我们自然可以在__autoload里 加载需要的类!

 

 

 

 

 

 

 

魔术方法的应用

 

TP中设置用户注册的做法: 把表单中接受到的信息,直接付给一个对象的属性,然后

 

对象 add()  用sql语句写到数据库中

 

 

 

 

 

具体的思路

 

在一个类中设置一个空数组,利用__set()把传进来的值放到数组中,然后利用 add方法 与数据库交互 ; 酱紫避免了与其他同名属性的冲突

 

都是使用魔法方法来进行操作

 

$date = array() 设置一个空数组

 

implode() :将数组按值进行分割

 

array_keys(array,value)  :获得数组中键名并以数组的形式 ; 前者数组名必选 , 后者数组值可选  ;  只选前者则返回所有键名 ; 两者选返回对应值得键名

 

 

 

2015/7/23

 

重载与重写

 

重写/覆盖  override:子类重写了父类的同名方法。只要子类有该方法只调用子类的无论参数是否一致

 

复制代码
<?php
//模仿重载的功能
class Circle {
    public function area() { $a = func_get_args(); $num = count($a); if ($num == 0) { echo '传入参数' . "\n"; } else if ($num == 1) { echo 3.14 * $a[0] . "\n"; //学会利用已有的条件进行分析  } else if ($num == 2) { echo $a[0] * $a[1] . "\n"; } } }
$c = new Circle(); $c->area(); $c->area(3);
class P { public function a() { echo "nihao"; } }
$b = new P(); $b->a(2123, 'sdf'); ?>
复制代码

 

 

 

重载 overload: 指存在多个同名方法,但参数类型/个数不同,传不同的参数,调用不同的方法。但是在PHP中,不允许存在多个同名方法.因此,不能够完成java,c++中的这种重载

 

但是,PHP的灵活,能达到类似的效果

 

复制代码
<?php 
    function __autoload($n){
        require('./' . $n . '.php'); echo "加载成功!"; } $test = new autoload_class(); $test->say(); ?>
复制代码

 

 

 

常量 (常量名全大写,不带$)

 

普通常量 :define('常量名',常量值); 全局有效.无论是页面内,函数内,类内,都可以访问 ;

 

类内常量 : 类常量 在类内用 const 声明即可;前面不用加修饰符,;且权限是public的,即外部也可以访问

 

作用域在类内,类似于静态属性 ;又是常量,则不可改.

 

其实就是"不可改变的静态属性",即是能够 类名::常量名 访问

 

 

 

 

 

 

 

魔术常量

 

1:无法手动修改他的值,所以叫常量

 

2:但是值又是随环境变动的,所以叫魔术

 

 

 

__FILE__  返回当前文件的路径+文件名

 

在框架开发或者是网站初始化脚本中,用来计算网站的根目录

 

 

 

__DIR__ 返回当前的文件路径

 

 

 

__LINE__  返回当前的行号

 

在框架中,可以用来在debug时,记录错误信息

 

 

 

__CLASS__ 返回当前的类名

 

 

 

__METHOD__ 返回当前的方法名

 

 

 

 

 

延迟绑定

 

注意 :static::方法名  表示调用 对象类中的方法 或者属性

 

注意 一般书写的时候public等权限修饰符在static前,增加规范可读性

 

 

 

 

抽象

 

抽象类 :类前加 abstract 是抽象类,是抽象方法抽象类不能 new 来实例化,有抽象方法,则此类必是抽象类;抽象类,内未必有抽象方法

 

抽象方法 :方法前加 abstract,抽象方法 不能有方法体,所以没有{} ; 而是直接();

 

子类 继承 抽象的父类 必须 重写父类的抽象方法!并且参数个数要一样

 

//利用面向对象思想实现不同语言首页欢迎!

 

//抽象类就是个模板,你们子类继承我的类和方法自己搞自己想要弄的东西

 

//比如我想要开发英语语言,只要增加一个子类,不用修改父类的东西

 

//所以面向对象是可插拔的

 

 

 

复制代码
<?php
//利用面向对象思想实现不同语言首页欢迎!
//抽象类就是个模板,你们子类继承我的类和方法自己搞自己想要弄的东西
//比如我想要开发英语语言,只要增加一个子类,不用修改父类的东西 //所以面向对象是可插拔的 abstract class Language { //抽象方法 public abstract function wel(); } class China extends Language { public function wel() { echo "欢迎!"; } } class English extends Language { public function wel($a) { echo "Welcome!"; } } $language = 'China'; $w = new $language(); //666 $w->wel(); ?> 
复制代码

 

说明 : 抽象类就是一个模板,我不用担心同类的类不会做,反正你只要根据我的模板做就不会错。从而达到兼容多种不同的情况 和 避免代码大量的修改 和 代码的规范(方法一致)

 

比如 :

 

公司网站要上线了,要选择什么数据库? 先弄个mysql开发着,到时候有问题再换也行。那么换数据库,会不会以前的代码又得重写? 其实不用担心,用抽象类!开发者,开发时,就以db抽象类来开发。不管上线时,真正用什么数据库,我只需要再写一份如下类(右图)即可。所以业务逻辑层不用改,因为都实现的db抽象类。

 

 

 

接口 

 

(没有括号) interface 接口名 {  }

 

类如果是一种事物/动物的抽象,那么 接口则是事物/动物的功能的抽象,即再把它们的功能各拆成小块自由组合成新的物种。

 

以人类为例, class Human 是人的草图而接口 是零件可以用多种零件组合出一种新特种来.

 

1、接口本身即是抽象的,内部声明的方法 默认也是抽象的.不用加 abstract

 

2、一个类可以一次性实现多个接口.语法用 implements 实现 (把我这几个功能实现了)

 

3、接口可继承另一个接口, 用extends ;注意实现时须把继承的接口的方

 

4、接口是一堆抽象方法的说明,不能加属性

 

5、接口就是供组装成类用的,封闭起来没有意义,因此方法只能是public

 

复制代码
<?php
/*
接口 就更加抽象了,比如一个社交网站,关于用户的处理是核心应用。
登陆 退出 写信 看信 招呼 更换心情
吃饭 骂人 捣乱 示爱 撩骚

这么多的方法,都是用户的方法,可写一个user类,全包装起来
但是,分析用户一次性使不了这么方法。于是分开多个类

用户信息类:{登陆,写信,看信,招呼,更换心情,退出}
用户娱乐类:{登陆,骂人,捣乱,示爱,撩骚,退出}
*/
interface UserBase { //注意没括号 public function login($u, $p); public function logout(); //注意是抽象方法  } interface UserMsg { public function wirteMsg($to, $title, $content); public function readMsg($from, $title); } interface UserFun { public function spit($to); public function showLove($to); } /* 作为调用者, 我不需要了解你的用户信息类,用户娱乐类, 我就可以知道如何调用这两个类 因为: 这两个类 都要实现 上述接口. 通过这个接口,就可以规范开发. */ class User implements UserBase { public function login($u, $p) { echo "用户登录"; } public function logout() { echo "用户注销"; } } ?> 
复制代码

 

 

 

包含类进来

 

include/require能够包含某个php文件,但是不知道是否调用过;改进使用魔术方法__aotoload($)

 

__autoload() : 如果调用某个不存在的类,在报错之前,系统会调用__autoload($n)函数,并把"类名"自动传给__autoload函数我们自然可以在__autoload里 加载需要的类!

 

 

 

★自定义 自动加载方法

 

通知系统,让系统知道--我自己写了一个自动加载方法,用这个spl_auto_register($n)

 

 

 

 

 

★方法中能定义一个类,但是想要执行类里面的东西,必须先动态调用方法(直接方法名),有return也不关事

 

 

 

 

 

 

 

异常

 

讨论:如何判断mysql类连接是否成功? 利用 在方法里面return?

 

实例化后返回一个对象,无法确定是否连接成功 。 return无法干扰,仍然是返回对象

 

解决这种问题,用异常类 Exception

 

 

 

 

 

注意 @mysql_connect();  //@表示忽略此处输出的错误

 

关闭所有的错误报告 : Error_reporting(0);

 

 

 

复制代码
     {
         protected $conn = NULL;

         public function __construct()
         {
             $this->conn = mysql_connect('localhost','root','111'); if (!$this->conn) //如果连接失败了,抛出错误  { $e = new Exception('失败了!',9); // throw $e; //抛出异常  } } } //若抛出异常,没有接受处理则会报错 try // 可能出现错误的代码并尝试捕捉错误信息  { $my = new mysql(); }catch(Exception $e) // 注意括号,处理错误  { echo $e->getMessage(); echo '错误代码',$e->getCode(); echo '错误文件',$e->getFile(); echo '错误行',$e->getLine();//抛出错误的行  } ?>
复制代码

 

 

转载于:https://www.cnblogs.com/xiong63/p/6057204.html

相关文章:

  • require.js与sea.js的区别
  • 11-13
  • Discuz! 6.x/7.x 全局变量防御绕过导致命令执行
  • 各类应用的简称
  • java的反射
  • Spring+AOP+Log4j 用注解的方式记录指定某个方法的日志
  • 使用Apache的Base64类实现Base64加解密
  • 【ARM-Linux开发】在win下开发的eclipse+yougatoo+jlink环境搭建
  • Python 绘图利器 —— ggplot
  • Linux下多网卡同网段多IP网络分流设定方法
  • 跟庄
  • SQL连接查询
  • 算法导论笔记之红黑树
  • Hibernate 系列教程10-组成关系
  • Java丨JDK与JRE
  • JAVA SE 6 GC调优笔记
  • java2019面试题北京
  • Java读取Properties文件的六种方法
  • JS题目及答案整理
  • select2 取值 遍历 设置默认值
  • sessionStorage和localStorage
  • uni-app项目数字滚动
  • v-if和v-for连用出现的问题
  • 使用parted解决大于2T的磁盘分区
  • 协程
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • #Linux(帮助手册)
  • #pragma 指令
  • ${ }的特别功能
  • (1) caustics\
  • (1)bark-ml
  • (2015)JS ES6 必知的十个 特性
  • (26)4.7 字符函数和字符串函数
  • (4)事件处理——(7)简单事件(Simple events)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (七)Knockout 创建自定义绑定
  • (实战篇)如何缓存数据
  • (数据结构)顺序表的定义
  • (小白学Java)Java简介和基本配置
  • (一)Java算法:二分查找
  • (译)2019年前端性能优化清单 — 下篇
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)ORM
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .dwp和.webpart的区别
  • .Net Core 中间件验签
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET开发人员必知的八个网站
  • @ModelAttribute 注解