PHP学习笔记(四)--面向对象

1、基本内容

注意事项:

  1. 无论是使用“$this->”还是使用“对象名->”格式,后面的变量是没有$符号的,如$this->value;
  2. 通过“类名::常量”方式类访问类常量的,如bastBall::Type;
  3. 在PHP中使用“垃圾回收”机制,不需要手动创建析构函数。不再使用的对象会自动清楚,释放内存;
  4. 对于成员方法,如果没有指定关键字,则默认是public,这一点与C++不同;
  5. 被protected修饰的类成员,可以在本类和子类中被调用,其它地方不可以,这也与C++不同;
  6. 在静态方法中,只能调用静态变量,而不能调用普通变量,而普通方法中可以调用静态变量;
  7. 在类内部访问静态成员使用“self::静态变量”,在类外部使用“类名::静态变量”;
  8. 构造函数__construct及析构函数__destruct不能声明为私有类型;
  9. finale修饰的类不可被再继承,也不能再有子类。finale修饰的方法不可以进行重写,也不可以被覆盖;
  10. 抽象类是一种不能被实例化的类,只能作为其它的父类来使用。抽象类包含变量、成员方法,至少要包含一个抽象方法。抽象类和抽象方法主要用于复杂的层次关系中。
  11. PHP只支持单继承,要想实现多继承就要使用接口。接口类中只能包含未实现的方法和一些成员变量。接口中的类成员必须使用public来修饰。接口类中的所有未实现的方法必须要在子类中实现;
  12. 类常量前面不加$符号。

 

【例1】类的定义及使用

<?php

    class SportObject{

       const TYPE='Sports';

       static $counter=0;

       private $name;

       private $age;

       private $sex;

       public function __construct($name,$age,$sex){

           $this->name=$name;

           $this->age=$age;

           $this->sex=$sex;

           self::$counter++;//计数

       }

       public function __destruct(){

           echo self::TYPE.'调用了析构函数';//类中访问常量使用self

       }

       public function PrintInfo(){

           echo $this->name.',';

           echo $this->age.',';

           echo $this->sex.'<p>';

       }

       public function IsBoy(){

           return $this->sex='' ? true : false;

       }

       public function ShowCounter(){

           echo '总共创建了:'.self::$counter.'个实例';

       }

    }

    $so=new SportObject('张三',22,'');

    $so->PrintInfo();//调用成员方法

    echo $so->IsBoy();

    echo SportObject::TYPE;//访问类的常量

    $sp2=new SportObject('张琴',25, '');

    $sp2->ShowCounter();

?>

2、继承

【例2】继承

<?php

    class SportObject{

       protected $name;

       private $age;

       private $sex;

       public function __construct($name,$age,$sex){

           $this->name=$name;

           $this->age=$age;

           $this->sex=$sex;

           self::$counter++;//计数

       }

      

       public function PrintInfo(){

           echo '姓名'.$this->name.'<p>';

       }

      

    }

    class BasketBallSports extends SportObject{

       private $height;

       public function __construct($name, $height){

           $this->name=$name;

           $this->height=$height;

       }

       public function PrintInfo(){//覆盖父类的方法

           echo '身高:'.$this->height.'<p>';

       }

    }

    $sp1=new BasketBallSports('郑钧', 188);

    $sp1->PrintInfo();

?>

 

3、多态

【例3】多态

<?php

    class Overloader

    {

       private $properties = array();

   

       function __get($property_name)

       {

           if(isset($this->properties[$property_name]))

           {

              return($this->properties[$property_name]);

           }

           else

           {

              return(NULL);

           }

       }

   

       function __set($property_name, $value)

       {

           $this->properties[$property_name] = $value;

       }

   

       public function __call($method, $p)

       {

          

           if($method == 'display')

           {

              if(is_object($p[0]))

                  $this->displayObject($p[0]);

              else

                  if(is_array($p[0]))

                     $this->displayArray($p[0]);

                  else

                     $this->displayScalar($p[0]);

           }

       }

   

       public function displayObject($p)

       {

           echo ("你传入的是个对象,内容如下:<br>");

           print_r($p);

           echo "<hr>";

       }

   

       public function displayArray($p)

       {

           echo ("你传入的是个数组,内容如下:<br>");

           print_r($p);

           echo "<hr>";

       }

   

       public function displayScalar($p)

       {

           echo ("你传入的是个单独变量,内容如下:<br>" . $p);

           echo "<hr>";

       }

    }

 

    $o = new Overloader();

    //调用 __set() 给一个不存在的属性变量赋值

    $o->dynaProp = "Dynamic Content";

    $o->display('Cat');

?>

 

4、抽象类

【例4】抽象类

<?php

    abstract class CommodityObject{

       protected $type;

       const CNAME='CommodityObject';

       static public function Show(){

          

       }

       public function __construct(){

           $this->type='通用类';

       }

       public function Display(){

           echo $this->type;

       }

       abstract function service($getName,$price,$num);

    }

    class MyBooks extends CommodityObject{

       function service($getName, $price, $num){

           echo '书名:'.$getName.'<p>';

           echo '价格:'.$price.'<p>';

           echo '数量:'.$num.'<p>';

       }

    }

    $book=new MyBooks();$book->service('PHP从入门到精通', 60, 3);

    $book->Display();

?>

 

5、接口

【例5】接口

<?php

    interface MPopedom{

       function popedom();

    }

    interface MPurview{

       function purview($name);

    }

    class Manager implements MPopedom,MPurview{

       function popedom(){

           echo '拥有会员的权限';

       }

       function purview($name){

           echo '拥有管理员的权限';

       }

    }

    $manager=new Manager();

    $manager->popedom();

    $manager->purview('张三');

?>

 

 

6、克隆对象

使用close关键字进行对象的复制,直接将一个对象赋值给另一个对象$object2=$object1,则object2是object1的引用。有时候单纯的克隆对象外,还需要克隆出来的对象可以拥有自己的属性和方法,这时可以使用__clone()方法来实现,在对象的克隆过程中调用该方法。

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

    }

    $book1=new SpoerObject();

    $book2=$book1;

    $book2->setType('computer');

    echo $book1->getType();//输出computer

    $book3=clone $book1;

    $book3->setType('mouse');

    echo $book1->getType();//还是输出computer

?>

 

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

       public function __clone(){

           $this->object_type='computer';

       }

    }

    $book1=new SpoerObject();

    $book2=clone $book1;

    echo $book2->getType();//输出computer

   

?>

 

7、对象比较及类型检测

使用“==”可以比较两个对象的内容是否相同,“===”可以比较两个对象的地址是否相同。

instanceof操作符可以检测当前对象是属于哪个类。一般格式为:

ObjectName instanceof ClassName

【例1】对象类型的比较

<?php

    class SpoerObject{

       private $object_type='book';

       public function setType($type){

           $this->object_type=$type;

       }

       public function getType(){

           return $this->object_type;

       }

    }

    $book1=new SpoerObject();

    $book2=$book1;

    $book3=clone $book1;

    echo ($book2==$book1 ? "true" : "false").'<p>';//true

    echo ($book2===$book1 ? "true" : "false").'<p>';//true

    echo ($book3==$book1 ? "true" : "false").'<p>';//true

    echo ($book3===$book1 ? "true" : "false").'<p>';//false

?>

 

【例2】

<?php

    class SportObject{   }//创建空类

    class BasketBallSports extends SportObject{

       private $height;

       public function __construct($height){

           $this->height=$height;

       }

       public function PrintInfo(){//覆盖父类的方法

           echo '身高:'.$this->height.'<p>';

       }

    }

    $sp1=new BasketBallSports( 188);

    echo ($sp1 instanceof BasketBallSports ? 'true' : 'false');//true

    echo ($sp1 instanceof SportObject ? 'true' : 'false');//true

?>

 

8、魔术方法

PHP中以两个下划线“__”开头的方法,例如__destruct、__construct、__clone等都称为魔术方法。如果要调用这些魔术方法必须在类中进行定义。

  1. __set()方法

当程序试图写入一个不存在或不可见的成员变量时,PHP会调用__set()方法。__set()包含两个参数,分别是变量名称和变量值,参数都不可省略。

 

  1. __get()方法

当程序调用一个未定义或不可见的成员变量时,可以通过__get()方法来读取变量值。__get()犯法有一个参数,表示要调用的变量名。

【例1】

<?php

    class SportObject{

       private $type='';

       public function __get($name){

           if(isset($this->$name)){

              echo "<p>变量".$name."的值为:".$this->$name;

           }else{//如果变量未定义

              echo "<p>变量".$name."未定义,初始化为0";

              $this->$name=0;

           }

       }

       public function __set($name,$value){

           if(isset($this->$name)){

              $this->$name=$value;

              echo '<p>变量'.$name.'已定义';

           }else{

              echo '<p>变量'.$name.'未定义,被初始化为'.$value;

              $this->$name;

           }

       }

    }

    $myComputer=new SportObject();

    $myComputer->type='DIY';

    echo $myComputer->type;

    $myComputer->name;

?>

运行结果为:

  1. __call()方法

当程序视图调用不存在或不可见的成员方法时,PHP会先调用__call()方法类存储方法名及其参数。__call()方法包含两个参数,即方法名和方法参数,其中方法参数是以数组的形式存在的。

<?php

    class SportObject{

       public function myDream(){

           echo '不存在要 调用的方法时调用此方法<p>';

       }

       public function __call($method,$parameter){

           echo '方法'.$method.'不存在';

           echo '参数信息:';

           var_dump($parameter);

           $this->myDream();

       }

    }

    $exam=new SportObject();

    $exam->dream('张三',22);

?>

 

  1. __sleep()方法和__wakeup()方法

PHP使用serialize()函数可以序列化对象。就是将类中的变量全部保存下来,对象中的类则只保存类名。当一个对象被串行化,PHP会调用__sleep方法(如果存在的话). 在反串行化一个对象后,PHP 会调用__wakeup方法. 这两个方法都不接受参数. __sleep方法必须返回一个数组,包含需要串行化的属性. PHP会抛弃其它属性的值. 如果没有__sleep方法,PHP将保存所有属性. 在程序执行前,serialize() 函数会首先检查是否存在一个魔术方法 __sleep.如果存在,__sleep()方法会先被调用,然后才执行串行化(序列化)操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致一个E_NOTICE错误。与之相反,unserialize()会检查是否存在一个__wakeup方法。如果存在,则会先调用 __wakeup方法,预先准备对象数据。

<?php

    class Connection {

        protected $link;

        private $server, $username, $password, $db;

       

        public function __construct($server, $username, $password, $db)

        {

            $this->server = $server;

            $this->username = $username;

            $this->password = $password;

            $this->db = $db;

            $this->connect();

        }

       

        private function connect()

        {

            $this->link = mysql_connect($this->server, $this->username, $this->password);

            mysql_select_db($this->db, $this->link);

            echo '连接数据库成功!<p>';

        }

       

        public function __sleep()

        {

            return array('server', 'username', 'password', 'db');

        }

       

        public function __wakeup()

        {

            $this->connect();

        }

       

    }

   

    $cnn = new Connection('localhost', 'root', null, 'students');

    $str=serialize($cnn);

    echo '序列化后的字符串'.$str.'<p>';

    $recnn=unserialize($str);

   

?>

 

输出结果:

 

  1. __toString()方法

当使用echo或print输出对象时,将对象转化为字符串。如果没有__toString()方法,直接输出对象会导致致命错误。注意,使用echo或print后面直接跟输出的对象,不可加入其它的字符。如echo ‘字符’.$myComputer不可以。

<?php

    class Connection {

        protected $link;

        private $server, $username, $password, $db;

       

        public function __construct($server, $username, $password, $db)

        {

            $this->server = $server;

            $this->username = $username;

            $this->password = $password;

            $this->db = $db;

            $this->connect();

        }

       

        private function connect()

        {

            $this->link = mysql_connect($this->server, $this->username, $this->password);

            mysql_select_db($this->db, $this->link);

            echo '连接数据库成功!<p>';

        }

       public function __toString(){

            $res='服务器名:'.$this->server.'<p>';

           $res.='用户名:'.$this->username.'<p>';

           $res.='密码:'.$this->password.'<p>';

           $res.='数据库:'.$this->db.'<p>';

           return $res;     }

    }

   

    $cnn = new Connection('localhost', 'root', '', 'students');

    echo $cnn;

?>

 

  1. __autoload()方法

 

__autoload()方法可以自动实例化所需要使用的类。__autoload()方法在指定的路劲下自动查找和该类同名称的文件,如果找到程序继续执行,否则报错。注意,类名必须与保存的文件名一致。

现在将上面5)中的类connection保存在当前工程目录下的connection.php中,index.php访问代码如下:

<?php

    function __autoload($class_name){

       $cname=getcwd().'\\'.$class_name.'.php';

       if(file_exists($cname)){

       include_once($cname);//动态引入类文件

    }else{

    echo '类路径'.$cname.'错误';

    }

    }

    $cnn = new Connection('localhost', 'root', '', 'students');

    echo $cnn;

?>

猜你喜欢

转载自blog.csdn.net/huzhizhewudi/article/details/84440504