zoukankan      html  css  js  c++  java
  • PHP 面向对象

    面向对象特性:
    
    *重用性 (每个模块都可以在项目中重复使用)
    
    *灵活性 (每个模块都很轻松被替换更改的)
    
    *拓展性(在模块上添加新功能是很方便的)
    
    类和对象的关系(类生成对象)
    
    物以类聚:相同特性的对象归为一个类,比如nba球员,都有想到的属性姓名,身高体重,球队号码,方法有跑步,跳跃,运球,投篮。将他们当做一个类,而乔丹,詹姆斯这些就是nba球员的实例,也叫对象;
    
    对象内部高内聚(特定的职能,所有相关的内容都封装在对象内部),对外低耦合(对象的一些可见属性和一些可见方法)
    
    用class 声明一个类,在类里面只能有 成员属性 和 成员方法!!!!不能有其他,在一个脚本中不能有两个同名类,实例化类可以有多个对象
    class Computer{
    
        public $text = "用关键字new实例化一个类";
    
        public function output(){
    
        echo $this->text;
    
        }
    }
    
    $computer = new Computer();
    
    $computer->output();//外部访问方法
    
    $computer->text();//外部访问属性
    
    $computer2 = new Computer();//可以实例化多个

    类的属性和方法 访问控制:
    public 公有 都可以访问 private 私有 只有类本身内部可以访问 protected 受保护 继承的子类和类本身内部可以访问,外部访问不了,如: $computer->output();如果output()方法设了protected,则报错。 类里面的方法: 方法里面调用一个属性,需要实例化类才能访问属性,而$this可以理解为是这个类的一个实例
    class Computer{    
    
        public $text = "用$this调用我";   
    
        public function output(){    
    
             echo $this->text;
    
        }
    
    }
    
    
    构造方法(实例化时执行)
    
    构造方法可以传递参数,在实例化时传入
    
    通过构造函数的参数传递,改变里面的属性使得每个实例对象不同
    
    class Computer{
    
       function __construct($arg){
    
           echo "我是构造方法,自动执行";    
    
           echo $arg;
    
       } 
    
    } 
    
    $conputer = new Computer("我是构方法的参数");
    析构方法:销毁时执行,不能有参数
    
    程序结束后自动执行,手动释放(当对象的引用全部销毁时)会使析构函数提前执行,不用等到程序结束后才调用
    
    当你 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了
    
    //对象引用  在PHP 中引用的意思是:不同的名字访问同一个变量内容.
    
    class A
    {
    
        function __destruct()
    
        {
    
            echo '====我是析构函数====';
    
        }
    
    }
    
    $a = new A();
    
    //提前执行析构函数的两个方法 unset($a);$a=null;
    
    echo "====正常执行我是先输出的=====";
    
    //两种对象引种的区别
    
    $a = $b;//这时$a和$b是两个独立的引用,unset($aa)只是删除了$a的引用,还有$b的引用,所以不会执行析构函数。改变其中一个为null,不会影响另外一个变量,也不会执行析构函数;
    
    $c = &$a;//两个的变量使用同个引用,c是a的影子,改变其中一个变量为null,两个都为null,会执行析构函数。但是只是unset($a),$c还在使用引用,只要有引用在不会执行析构函数;
    
    //对象的引用用于访问对象的属性和方法,所以$a $b $c都可以访问对象的属性方法; 
    
    //当一个对象的所有引用被删除后,才会触发析构函数
    
    //总结:如果程序大,对象引用尽量使用&,节省内存,清除也方便。设其中一个为Null,其他都为Null;
    
    //变量引用 (默认变量赋值会独立开辟一个内存存放内容)
    
     //PHP 的引用允许你用两个变量来指向同一个内容
    
    $a="AB"; 
    
    $b =&$a;
    
    echo $a;//这里输出:AB
    
    echo $b;//这里输出:AB 
    
    $b="EF"; 
    
    echo $a;//这里$a的值变为EF 所以输出EF 
    
    echo $b;//这里输出EF  <?php
    
    $a = 1;
    
    $b = $a;
    
    echo $a;
    
    //在此之前,b都是和a共用内存空间的。
    
    xdebug_debug_zval('b');
    
    $a = 2;//a作出了改变,此时b才会有自己的空间
    
    xdebug_debug_zval('b');
    
    ?>
    
    //函数引用
    
    <?php
    
    function test(&$a){ 
    
    $a=$a+100; 
    
    } 
    
    $b=1; 
    
    echo $b;//输出1 test($b); //这里$b传递给函数的其实是$b的变量内容所处的内存地址,通过在函数里改变$a的值 就可以改变$b的值了 echo "<br>"; echo $b;//输出101
    
    ?>//函数的引用返回
    
    <?php
    
    function &test()
    {     
    static $b=0;//申明一个静态变量     
    $b=$b+1;     
    echo $b;    
     return $b; 
    }
    $a=test();//这条语句会输出 $b的值 为1 相当于$a=$b
    $a=5; $a=test();//这条语句会输出 $b的值 为2 也是$a=$b$a=&test(); //这条语句会输出 $b的值 为3 $a=&$b,所以b会随a变了$a=5; $a=test();//这条语句会输出 $b的值 为6
    ?>
    赋值和克隆的区别:
    
    $a=$b(独立引用)和$a=&$b(同一引用)这种赋值方式,指向的是同一个对象,同一块内存空间;
    
    $a=clone $b这种赋值方式,则是指向另一个新的对象,另一个块新的内存空间。
    
    <?php
    class mm {
    
        public $name = 'Peter';
    
    }
    
    $a = new mm();
    
    $b = $a; 
    
    $c = &$a;
    
    $d = clone $a; 
    
    $b->name = "Anne";
    
    echo $a->name,"
    ",$b->name,"
    ",$c->name,"
    ",$d->name;//输出为:Anne Anne Anne Peter
    
    ?>
    类常量
    内部访问 self::常量名
    
    外部访问不需要实例化:类名::常量名
    class Computer{    
    
        const yh = 12;    
    
        const yh2 = self::yh+1;
    } 
    var_dump (Computer::yh2);
    $this 和 self 的区别
    
    一个是对象$this 相当于实例化后,可以说除了静态和const常量,基本上其他都可以使用this联络 ;
    
    self则是类本身 self可以访问本类中的静态属性和静态方法,可以访问父类中的静态属性和静态方法。用self时,可以不用实例化的
    
    类的继承
    
    存在意义:把相同的属性方法抽出来,让子类继承
    
    extends 后只能一个逗号,就是说只能继承一个父类,单继承
    class dad{     
    
         function eat(){         
    
              echo "我是父类的方法,子类可以继承我的方法";
    
         }
    
    }
    
    class boy extends dad{
    
    } 
    
    $boy = new boy();$boy->eat();
    子类也可以覆盖父类的方法
    
    子类没有构造方法时,会调用父类的构造方法,有则调用自己的,
    用关键字 parent:: __construct();可以调用父类的构造方法final关键字加在类前面就不会被继承;加到方法面前,此方法就不会被重写
    
    命名空间(解决命名冲突问题)
    利用文件系统不用目录的原理
    被引入的php文件中加入 namespace 目录子目录;
    使用时调用:new 目录子目录类名();如 new comsessioncomputer();
    受命名空间影响的有,类(包括抽象类,traits),接口,函数,常量(const和define都是用来声明常量的(它们的区别不详述),但是在命名空间里,define的作用是全局的,而const则作用于当前空间。)
    
    要注意的是,当前脚本文件的第一个命名空间前面不能有任何代码,下面的写法都是错误的:
    //例一
    
    //在脚本前面写了一些逻辑代码
    
    <?php
    
    $path = "/";
    
    class Comment { }
    
    namespace Article;
    
    ?>
    
    //例二
    
    //在脚本前面输出了一些字符
    
    <html></html>
    
    <?php
    
    namespace Article;
    
    ?>


    为什么要说第一个命名空间呢?因为同一脚本文件中可以创建多个命名空间。
    <?php
    
    //创建一个名为'Article'的命名空间namespace Article;
    
    //此Comment属于Article空间的元素class Comment { }
    
    //创建一个名为'MessageBoard'的命名空间namespace MessageBoard;
    
    //此Comment属于MessageBoard空间的元素class Comment { }
    
    ?>
    由于每次调用都要写上路径,很麻烦,所以出现use的用法(use引入必须带类名或者函数名)
    在调用时先用use引入,use 目录子目录类;还可以起个别名区别 as
    use ventersessioncomputer;
    
    use ventercomputer as computer2;
    
    new computer();
    
    new computer2();
    
    函数的话记得带上function
    
    use function ventersessioncomputer;
    
    computer();
    
    常量记得带上const
    
    use const ventersessioncomputer;
    
    var_dump(computer);
    重点:在命名空间里面调用全局的类,函数,常量的区别,
    页面a定义了命名空间 namespace venter;
    引入b页面(全局空间)后,此时想调用b页面的类,必须:
    New venter() 加个代表全局空间下的 但是调用函数和常量时,就不需要加,因为他会自动寻找,向全局寻找。 类自动加载: 当你实例化一个类时,这个类不存在,就会自动执行我们写的 function __autoload($className){},
    在这个自动函数的内部去执行我们想要操作的代码,参数就是我们实例化的类名,因此可以根据参数去引入php文件。 __autoload将被淘汰,使用新的函数 spl_autoload_register();参数可以传函数名或者匿名函数
    spl_autoload_register(function($a){
    
    echo $a;
    
    }
    
    );
    
    new Computer();
    
    或者
    
    function aaa($a){
    
    echo $a;
    
    }
    
     
    
    spl_autoload_register('aaa');
    
    new Computer();
    
    或者类的调用方法
    
    class momo
    
    {
    
    function aaa($a){
    
    echo $a;
    
    }
    
    }
    
    spl_autoload_register([new momo],'aaa');
    
    new Computer();
    利用命名空间和自动加载实现项目自动引用
    1,文件目录就和命名空间名一样,文件名和类名一样 new modelsimooc() 就是在models文件下的imooc.php文件,
    2,然后利用spl_autoload_register(function($classname){
    include str_replace("\","/",$classname.".php");
    });
    这里的作用是modelsimooc替换掉models/imooc.php 引入
    而imooc.php文件中必须命名 namespace models;
    
    static 静态
    
    存在的价值,为了让对象公用一些数据,做到统一性
    
    当属性和方法被定义为 static 时就变成类的属性和方法,不属于对象的,不需要实例化
    
    外部访问 类名::$aa 
    内部访问 self::$aa 或者static::$aa;
    子类访问父类 parent::$aa; 静态方法不能调用非静态属性 因为 $this代表实例化对象,而这里是类,不知道 $this 代表哪个对象
    class person{
    
    public static $aa ="a";
    
    public static function eat(){
            echo self::$aa;
            echo static::$aa;
        }
    }
    class boy extends person{
        public function eat2(){
            echo parent::$aa;
        }
    }
    echo(boy::eat2());
    后期静态绑定:
    class A{
    
    public static function who(){
    
    echo "A类的who方法";
    
    }
    
    public static function test(){
    
    self::who(); 
    
    // static::who();
    
    }
    }
    
    class B extends A{
    
    public static function who(){
    
    echo "B类的who方法";
    
    }
    
    }
    
    B::test();
    如果是self::who(); 输出的是A类的who方法,说明调用的是A自身,static::who();会根据上下文作处理,类B调用就使用B里面的who()
    
    魔术方法
    __set(
    $var,$val) 设置私有属性,当外部调用设置一个私有属性时会自动执行这个方法, __get($var)获取私有属性,原理是外部调用一个私有属性时会自动执行这个方法 例子:
    class test{
    
    private $abc = "";
    
    private $ccc = "";
    
    public function __set($var,$val){
    
    $this->$var = $val;
    
    }
    
    public function __get($var){
    
    return $this->$var;
    
    }
    
    }
    
    $test = new test();
    
    $test->abc = 'abc';
    
    var_dump($test->abc);
    __isset($var)方法,当外部调用isset($test-abc)访问一个不能访问的属性时,就会自动执行 isset()或者empty() 都会触发__isset()方法
    __unset($var),当外部想删除一个私用属性时,会自动执行
    以上是属性的重载
    
    __call,__callStatic是属于方法的重载,不是重写
    
    __call($func方法名,$arguments参数)当外部调用一个没有定义的方法时,就会调用
    
    __callStatic($meethod,$arg)当调用一个不存在的静态方法时,会自动执行 注意在function 前也要加入 static 因为是静态方法
    
    __invoke($rag)当实例化一个类后,把这个对象变量当成函数调用时,会自动执行 
    例如:$test = new test();
    $test("go....");
    
    __toString() 当对象被当成string使用时,会执行,比如 echo($test);
    
    __clone方法的一些应用
    当一个对象被克隆时,会调用__clone,此时可以在里面执行一些逻辑,比如不想让某些值被克隆,或者初始化一些属性的值
    
    对象拷贝:
    浅拷贝:是地址传递(对象是浅拷贝)
    深拷贝:复制一份,新开辟一块内存(普通变量是深拷贝)
    
    加clone 使对象成为深拷贝,互不影响;
    $a = new A();
    $b = clone $a;
    
    __clone()当使用clone时,会自动执行
    $a = new A();
    $b = clone $a; 在A类中会执行__clone()
    例子:
    class A{
    
    public $obj = null;
    
    public function __clone(){
    
    $this->obj = clone $this->obj;//开辟了新空间给克隆的对象
    
    }
    
    }
    
    Class B{
    
    public $sex = 0;
    
    }
    
     
    
    $a = new A();
    
    $a->obj= new B();
    
    $b = clone $a;
    
    $b->obj->sex = 1;
    
    var_dump($a->obj->sex);
    类型约束
    class A{
    
    public $obj = null;
    
    public function go(){
    
    echo "googogogogo";
    
    }
    
    }
    
    class B{
    
    public function go(){
    
    echo "bbbbbb";
    
    }
    
    }
    
    Function test(A $a){
    
    $a->go();
    
    }
    
    test(new A());//必须是A的实例
    
    
    trait 关键字
    
    解决单继承问题 配合use 使用
    trait A{
    
    public function a(){
    
    echo "aaaaa";
    
    }
    
    }
    
    trait B{
    
    public function b(){
    
    echo "bbbb";
    
    }
    
    }
    
     
    
    Class test{
    
    use A,B;
    
    public function c(){
    
    echo "cccc";
    
    }
    
    }
    
     
    
    $test = new test();
    
    $test->a();
    
    $test->b();
    
    $test->c();
    
    
    接口
    
    可以理解为类的模板 不能直接被实例化
    
    用instanceof 判断某个对象是否实现了某个接口
    接口可以继承接口,但是类必须实现接口所有的方法
    interface person {
    
    public function eat();
    
    public function sleep();
    
    }
    
    class man implements person{
    
    public function eat(){
    
    echo "chichi吃吃";
    
    }
    
    public function sleep(){
    
    echo "shuishushi";
    
    }
    
    }
    
    $aaa = new man();
    
    $aaa->eat();
    
    //接口继承 两种方法 
    
    interface aa {
    
    public function eat();
    
    }
    
    interface bb {
    
    public function sleep();
    
    }
    
    interface person extends aa,bb{
    
    //person就直接继承了两种方法
    
    }
    
    class man implements person{
    
    public function eat(){
    
    echo "chichi";
    
    }
    
    public function sleep(){
    
    echo "shuishuishui";
    
    }
    
    }
    
    //或者 直接实现两种接口
    
    class man implements aa,bb{
    
    public function eat(){
    
    echo "chichi";
    
    }
    
    public function sleep(){
    
    echo "shuishuishui";
    
    }
    
    }
    
    //接口里面可以利用 const 定义一个常量 
    
    interface person {
    
    const aa = "bbb";
    
    public function eat();
    
    public function sleep();
    
    }
    
    echo person::aa;
    抽象类:
    
    (比如人和动物都会呼吸方法都一样,此时就不需要每个类去实现不同的呼吸方法,吃东西的方法不同,所以在类中各自实现逻辑)抽象类的子类只需要实现抽象方法;
    
    内部有自己的执行方法
    
    abstract class person {
    
    public function holiday(){
    
    echo '我是抽象类自己实现的方法';
    
    }
    
    //抽象方法,以分号结束,无方法体;抽象类中至少要有一个抽象方法
    
    abstract public function eat();
    
    }
    
    class man extends person{
    
        public function eat(){
    
        $this->holiday();//直接调用即可
    
        }
    
    }
    
    $aaa = new man();
    
    $aaa->eat();
    
    
    单例模式:
    
    让一个类只会被实例化一次,节省内存空间
    
    先把构造函数和克隆函数变成私用属性
    
    class test{
    
    private static $_instance = null;//依靠属性存储实例对象判断是否已经实例过
    
    private function __construct(){
    
    // 私有后将不会被外部实例
    
    }
    
    private function __clone(){
    
    // 私有后将不会被外部克隆
    
    }
    
    public static function getInstance(){
    
    if(!(self::$_instance instanceof self)){
    
    // instanceof判断是否是当前的实例,不是的话就实例化赋值,否则就返回
    
    self::$_instance = new self();
    
    }
    
    return self::$_instance;
    
    }
    
    }
    
    $test1 = test::getInstance();
    
    $test2 = test::getInstance();
    
    $test3 = test::getInstance();
    
    var_dump($test1);
    
    var_dump($test2);
    
    var_dump($test3);
    
    // 输出结果object(test)#1 (0) { } object(test)#1 (0) { } object(test)#1 (0) { }
    
    
    工厂模式:
    
    就是在多处实例化一个类,当这个类名需要改变时,就会导致大量地方需要更改,使用工厂模式避免这种情况发生
    class A{
    
    public function a(){
    
    echo 'aaa';
    
    }
    
    public function c(){
    
    echo 'ccc';
    
    }
    
    public function b(){
    
    echo 'bbb';
    
    }
    
    }
    
    class cashe{
    
    public static function factory(){
    
    return new A();//当业务逻辑变化时,只需要改此处
    
    }
    
    }
    
    $cashe = cashe::factory();
    
    $cashe->a();
    面向对象功能汇总
    
    有继承功能,必须有访问的控制,
    (私有公有属性),
    static静态关键字来保存一些公用的数据,
    重写对父类的方法属性重定义,
    final关键字不允许重写或者继承,
    访问静态属性的几个方法,
    接口中的方法是不用具体实现的,
    在类中才实现,而且必须实现接口中所有的方法,
    因为有了不同的实现方法逻辑,不同的对象产生不同的表现,这叫多态,
    存在与接口与类之间的叫抽象类,可以有一部分可以实现,一部分不用实现
    /*--------------多态的一个应用实例 模拟USB设备的使用------------------*/
    //一个USB的接口
    
    interface USB{
    
    function mount();//装载USB的方法
    
    function work();//USB工作的方法
    
    function unmount();//卸载USB的方法
    
    }
    
    //定义一个USB设备 U盘
    
    class Upan implements USB{//实现USB接口
    
    function mount(){
    
    echo " U盘 装载成功<br/>";
    
    }
    
    function work(){
    
    echo "U盘 开始工作<br/>";
    
    }
    
    function unmount(){
    
    echo "U盘 卸载成功<br/>";
    
    }
    
    }
    
    //定义一个USB设备 USB鼠标
    
    class Umouse implements USB{//实现USB接口
    
    function mount(){
    
    echo " USB键盘 装载成功<br/>";
    
    }
    
    function work(){
    
    echo "USB键盘 开始工作<br/>";
    
    }
    
    function unmount(){
    
    echo "USB键盘 卸载成功<br/>";
    
    }
    
    }
    
    //定义一个电脑类
    
    class Computer{
    
    //使用USB设备的方法
    
    function useUSB ($usb){//$usb参数表示 使用哪种USB设备
    
    $usb->mount();//调用设备的 装载方法
    
    $usb->work();//调用设备的 工作方法
    
    $usb->unmount();//调用设备的卸载方法
    
    }
    
    }
    
    //定义一个电脑的使用者的类
    
    class PcUser{
    
    //安装USB的方法
    
    function install(){
    
    //首先拿来一台电脑
    
    $pc=new Computer;
    
    //拿来一些USB设备
    
    $up=new Upan;//拿来一个U盘
    
    $um=new Umouse;//拿来一个USB鼠标
    
    //把USB设备插入电脑, 使用电脑中使用USB设备的方法 来调用 要插入的设备
    
    $pc->useUSB($up);//插入U盘
    
    $pc->useUSB($um);//插入USB鼠标
    
    }
    
    }
    
    //实例化一个电脑用户
    
    $user=new PcUser;
    
    $user->install();//安装设备
    
    /*-------------输出内容--------------
    
    U盘 装载成功
    
    U盘 开始工作
    
    U盘 卸载成功
    
    USB键盘 装载成功
    
    USB键盘 开始工作
    
    USB键盘 卸载成功
    
    -----------------------------------*/
  • 相关阅读:
    Node Sass version 5.0.0 is incompatible with^4.0.0
    解决vue-cli引入sass,报错:this.getResolve is not a function问题
    解决nuxt官方脚手架的一些坑:1、支持es6+语法 2、样式支持sass
    针对【create-nuxt-app新版本v3.2.0】构建项目时没有server配置以及运行后弹出收集匿名数据选项等问题的解决方法
    create-nuxt-app创建出来的目录没有server文件夹
    Redis安装(Windows环境下Redis安装)
    koa2中间件,路由,cookies
    用同步的写法来执行异步操作, async, awiat
    koa2 安装与启动
    练习:自己写一个容器ArrayList集合 一一数组综合练习
  • 原文地址:https://www.cnblogs.com/sgm4231/p/9816409.html
Copyright © 2011-2022 走看看