PHP之路 PHP基础【第十篇】面向对象

定义类

类的定义

定义类的格式:class ClassName{}
类中有两个元素:成员属性和成员方法

类的成员属性定义

成员属性介绍

类的成员属性,就是指某个类具有的公共的特征、特性;
类中定义的变量,就是类的成员属性;
类的成员属性和普通变量的区别:类的成员属性必须要带权限修饰符,而普通变量不需要。

权限修饰符

成员属性必须要加权限修改符,否则报错。
public(公共权限):在任何地方都可以访问,主要包括:类外、本类中、子类中都可以访问。
private(私有权限):只能在本类中被访问,在类外和子类中都无权访问。
protected(受保护的权限):只能在本类中和子类中被访问,在类外不能被访问。

类的成员方法定义

类的方法,就是某个类的公共的的行为或动作;
类的成员方法,与普通函数一样,都有返回值和参数;
成员方法与普通函数区别:成员方法只能存在于类中,成员方法定义前可以添加访问权限修饰符;
提示:成员方法可以省略权限修饰符,默认访问权限是public。

实例化对象

1、实例化对象的含义

定义类是为了生产对象,如果不生产对象,类就没有意义。
一个类可以产生千千万万个对象,对象帮我们干活。
对象实例化:从一个类上来生产对象过程,就是类的实例化。

2、语法格式

使用new关键字来创建对象。

对象属性操作

<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个类
class Hacker
{
    //公共的成员属性
    public $name = "张三";
}

//创建学生类的对象
$obj = new Hacker;

//修改属性:给成员属性重新赋值
$obj->name = "鸣人";
//添加属性:给当前对象添加一个新属性
$obj->age = 18;
//删除属性:使用unset()可以删除变量、数组元素、对象属性等
unset($obj->age);
//读取属性
echo "我的名字叫:{$obj->name}";
demo

对象方法操作

<?php

//定义一个类
class Hacker
{
    //公共的成员(对象)方法
    public function showInfo($name,$age)
    {
        return "{$name}的年龄是{$age}岁!";
    }
}

//创建学生类的对象
$obj = new Hacker;
//调用对象的方法
echo $obj->showInfo('小网站',25);
demo

this关键字

$this代表当前对象,是到当前对象的一个引用;
$this更像是一个对象指针,指向当前对象;
$this只能用在对象方法定义中,去调用对象的成员属性或成员方法。
只有创建对象后,$this变量才存在。类不会自动运行。 
<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个类
class Hacker {
    //私有的成员属性:类外无法访问
    private $name = "张三丰";
    private $age  = 24;

    //受保护的成员方法
    protected function showLine(){
        return "<hr>";
    }
    //公共的成员(对象)方法
    //$this变量只能在成员方法中使用
    public function showInfo()     {
        //在成员方法中,使用$this变量代替传递进来的$obj对象
        //$this和$obj指向的是同一个对象
        $str = "<h2>{$this->name}的基本信息</h2>";
        $str .= $this->showLine();
        $str .= "{$this->name}的年龄是{$this->age}岁!";
        echo $str;
    }
}
//创建学生类的对象
$obj = new Hacker;
//调用对象的方法
$obj->showInfo();
demo

类常量的定义

可以把在类中始终保持不变的值定义为常量,例如:圆周率、班级名称等。
常量的值必须是一个定值,不能修改,也不能删除;
类常量就是类的常量,是与类相关的,与对象无关。
类常量在内存中只有一份,不管创建多少个对象。
类常量可以极大节省服务器内存,可以被所有对象去共享。

类常量没有权限,只有属性和方法才会有权限。
使用const来定义类的常量(局部常量),只能在局部作用域下使用;define()定义常量是全局常量,在任何地方都可以使用。
<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个类
class Hacker{
    //声明类常量
    const DB_HOST = "localhost";
    const DB_USER = "root";
    const DB_PASS = "root";

    //公共的成员方法
    public function showInfo() {
        $str = "<h2>在类内访问类常量</h2>";
        $str .= "主机名:".Hacker::DB_HOST;
        $str .= "<br>用户名:".Hacker::DB_USER;
        $str .= "<br>密码:".Hacker::DB_PASS;
        echo $str;
    }
}
//用静态化方式,直接访问类常量,不需要创建对象
$str = "<h2>在类外访问类常量</h2>";
$str .= "主机名:".Hacker::DB_HOST;
$str .= "<br>用户名:".Hacker::DB_USER;
$str .= "<br>密码:".Hacker::DB_PASS;
echo $str;

//创建学生类对象
$obj = new Hacker();
$obj->showInfo();
demo

构造方法 

当使用new关键字创建对象时,第1个自动调用的方法,就是构造方法;
构造方法的名称是固定的:void __construct ([ mixed $args [, $... ]] )
构造方法可以带参数,也可以不带参数;构造方法不是必须的,是可选的;
构造方法的作用:对象初始化。例如:给对象属性赋值、数据库对象初始化(连接、选择数据库)
构造方法一定是成员方法。构造方法的权限可以自己指定。
构造方法一般不需要主动调用,都是自动调用的。
<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个类
class Hacker{
    //私有的成员属性:在项目中,成员属性没有具体的数据,可以有默认值
    //所有数据都来自外部传递,所有属性一般都是私有的
    private $name;
    private $sex;
    private $age;

    //公共的构造方法
    public function __construct($name2,$sex2,$age2){
        $this->name = $name2;
        $this->sex  = $sex2;
        $this->age  = $age2;
    }

    //公共的自我显示的方法
    public function showInfo(){
        $str = "姓名:{$this->name}";
        $str .= "<br>性别:{$this->sex}";
        $str .= "<br>年龄:{$this->age}";
        echo $str;
    }
}
//创建学生类的对象
$obj = new Hacker("张三四","男",26);
$obj->showInfo();
demo

析构方法

对象销毁前自动调用的方法,就是析构方法; 
析构方法的名称是固定的:void __destruct ( void )
析构方法不带任何参数;
析构方法一定是成员方法。
析构方法的作用:垃圾回收工作,例如:断开到MySQL的连接

对象何时销毁

网页执行完毕时,对象会自动销毁;
使用unset()函数手动销毁对象 
<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个学生类
class Hacker {
    //公共的析构方法
    public function __destruct()
    {
        echo "对象即将销毁!<br>";
    }
}
//创建学生类对象
$obj = new Hacker();
//手动删除对象
unset($obj);
echo "这是网页的最后一行代码";
demo

静态属性和静态方法

static关键字修饰的属性,就是静态属性;
static关键字修饰的方法,就是静态方法;
静态属性:就是类的属性,与类相关,与对象无关;
静态方法:就是类的方法,与类相关,与对象无关;
类的东西(类常量、静态属性、静态方法),通过"类名::"来调用;
静态属性或静态方法,在内存中只有一份,被所有对象去共享;
静态属性或静态方法的好处:就是为了节省内存。例如:创建了100个对象,而静态属性只有一份。
静态属性和类常量的区别:类常量在一次HTTP请求过程值永远不变;但是静态属性可以改变。
静态属性和静态方法,都可以加权限控制符,而类常量没有权限。


$this是指向当前对象的指针,而self是指向当前类的指针;
$this关键字用来调用对象的属性和方法;
self用来调用类常量、静态属性、静态方法;
$this关键字只能在成员方法中使用;
self关键字可以在成员方法和静态方法中使用;
<?php
header('Content-Type: text/html; charset=utf-8');
//定义一个学生类
class Hacker
{
    //私有的保存人数的静态属性:所有对象共享
    private static $count = 60;
    //公共的静态方法
    public static function showInfo()
    {
        $str = "当前文件名:".__FILE__;
        $str .= "<br>当前函数名:".__FUNCTION__;
        $str .= "<br>当前方法名:".__METHOD__;
        $str .= "<br>班级人数:".Hacker::$count;
        echo $str;
    }
}
//在类外访问公共的静态方法
//访问类的内容(类常量、静态属性、静态方法),不需要创建对象,直接访问
Hacker::showInfo();
demo1
<?php
header('Content-Type: text/html; charset=utf-8');
//定义一个学生类
class Hacker
{
    //定义类常量
    const TITLE = "<h2>第2期就业班</h2>";
    //私有的保存人数的静态属性:所有对象共享
    private static $count = 60;
    //公共的静态方法:在静态方法中$this不存在
    public static function showInfo()
    {
        $str = self::TITLE;
        $str .= "当前文件名:".__FILE__;
        $str .= "<br>当前函数名:".__FUNCTION__;
        $str .= "<br>当前方法名:".__METHOD__;
        $str .= "<br>班级人数:".self::$count;
        echo $str;
        //var_dump($this); $this不能存在于静态方法
    }
}
//在类外访问公共的静态方法
//访问类的内容(类常量、静态属性、静态方法),不需要创建对象,直接访问
//对象可以调用:成员属性、成员方法、静态方法
$obj = new Hacker();
$obj->showInfo();
demo2

内存的分配情况

值传递
	所谓"值传递",就是将一个变量的"数据"或"值",复制一份,传递给另一个变量;
	这两个变量之间没有任何关系,修改其中一个变量的值,另一个变量的值不受影响;
	默认情况下,PHP值传递的数据类型有:字符串型、整型、浮点型、布尔型、数组型、NULL
	在栈中分配内存

引用传递
	所谓"引用传递",就是将一个变量的"数据地址",复制一份,传递给另一个变量;
	这两个变量指向“同一个地址”,修改其中一个变量的值,另一个变量的值也会受影响;
	默认情况下,PHP引用传递的数据类型有:对象和资源。
	在堆中分配内存
<?php
header('Content-Type: text/html; charset=utf-8');
//值传递的变量,变成"引用传地址"
//实例:定义一个函数,实现给数组添加元素
$arr1 = ['10010','张三丰',24];
$school1 = "北京科技大学";

function addElement(&$arr2,$school2)
{
    $arr2[] = $school2;
    print_r($arr2);
}

//调用函数
addElement($arr1,$school1);

//在函数外打印$arr1
print_r($arr1);
demo

类的封装性

什么是类的封装性
	类的三大特性:封装性、继承性、多态性;
	封装性:将敏感的数据保护起来,不被外界访问;还可以理解为,将一个功能的方方面面,封装成一个整体,即类;
	类的封装性,是通过访问权限修饰符来实现的;
	提示:在项目中,属性基本都是私有的。通过公有的方法,对私有的属性进行赋值和取值。


访问权限修饰符
	public(公共的权限):在任何地方都可以被访问,主要是类内、类外、子类中都可以被访问。
	private(私有的权限):只能在本类中被访问,类外和子类中无权访问。
	protected(受保护的权限):只能在本类中和子类中被访问,在类外不能访问。
<?php
header('Content-Type: text/html; charset=utf-8');
//定义一个数据库工具类
class Db
{
    //私有的数据库配置信息
    private $db_host; //主机名
    private $db_user; //用户名
    private $db_pass; //密码
    private $db_name; //数据库名
    private $charset; //字符集
    private $link; //连接对象

    //公共的构造方法:数据库对象初始化
    public function __construct($config=array())
    {
        $this->db_host = $config['db_host'];
        $this->db_user = $config['db_user'];
        $this->db_pass = $config['db_pass'];
        $this->db_name = $config['db_name'];
        $this->charset = $config['charset'];
        //一个方法只做一件事
        $this->connectDb(); //连接MySQL服务器
        $this->selectDb(); //选择数据库
        $this->setCharset(); //设置字符集
    }

    //私有的连接MySQL服务器方法
    private function connectDb()
    {
        if(!$this->link = @mysqli_connect($this->db_host, $this->db_user, $this->db_pass))
        {
            echo "连接MySQL服务器失败!";
            die();
        }
    }

    //私有的选择数据库的方法
    private function selectDb()
    {
        if(!mysqli_select_db($this->link, $this->db_name))
        {
            echo "选择数据库{$this->db_name}失败!";
            die();
        }
    }

    //私有的设置字符集
    private function setCharset()
    {
        mysqli_set_charset($this->link, $this->charset);
    }

    //公共的析构方法
    public function __destruct()
    {
        mysqli_close($this->link); //断开MySQL连接
    }
}

//创建数据库类的对象
$arr = array(
        'db_host' => 'localhost',
        'db_user' => 'root',
        'db_pass' => 'root',
        'db_name' => 'mysql',
        'charset' => 'utf8'
    );
$db = new Db($arr);
var_dump($db);
demo

类的继承性

什么是类的继承性

CSS样式继承:父标签定义的样式,可以在子标签中直接使用。相同的样式只写一遍,减少代码量。
如果一个B类拥有了A类的所有特征信息,我们就说B类继承了A类。
A类可以称为:基础类(最顶层的类)、父类、上层类。
B类可以称为:最终类(最终的类)、子类、下层类。

提示:如果多个子类拥有相同的属性和方法,可以将相同的属性和方法提取出来,放到“父类”中,
然后,再创建子类并继承父类;这样一样,重复的代码只写一遍,减少代码量,提高工作效率。

为什么要使用类的继承?是为了实现功能的升级和扩展。
	功能的升级:原来有的功能,在子类进行完善。
	功能的扩展:原来没有的功能,在子类增加新功能。
单继承demo

parent关键字  

self代表当前类,parent代表父类。
self和parent可以存在于所有方法(成员方法和静态方法)中。
self用来调用本类的内容,包括:类常量、静态属性、静态方法、成员方法;
parent用来调用父类的内容,包括:类常量、静态属性、静态方法、成员方法;
self和parent都使用范围解析符"::"来调用其它内容。
语法:parent::类常量 | 静态属性 | 静态方法 | 成员方法
<?php
header('Content-Type: text/html; charset=utf-8');

//定义一个学生类
class Hacker
{
    const TITLE = "PHP第69期就业班";
    protected static $count = 60;
}

//定义一个传智学生类
class Minren extends Hacker
{
    const TITLE = "PHP第70期就业班";
    protected static $count = 160;
    public function showInfo()
    {
        $str = "父类常量:".parent::TITLE;
        $str .= "<br>子类常量:".self::TITLE;
        $str .= "<br>父类静态属性:".parent::$count;
        $str .= "<br>子类静态属性:".self::$count;
        echo $str;
    }
}
//创建传智学生类对象
$obj = new Minren();
$obj->showInfo();
parent关键字demo

类的多态

什么是类的多态

    类的多态,就是类的多种形态。
    类的多态主要指方法重载或方法重写。
    方法重载:在同一个类中定义两个同名方法,PHP不支持。
    方法重写:在子类中定义一个与父类同名的方法,就是“方法重写”。
   
    为什么要重写方法?主要是实现功能的升级。父类中有的方法,子类中再用同样的名字再定义一次,
    一般来说,子类中方法的功能比父类更完善、更详尽。
    
方法重写的要求

    子类中重写的方法,要与父类中的方法同名;
    子类中重写的方法形参个数,要与父类中的同名方法形参个数一致;
    子类中重写的方法类型,要与父类中同名方法类型一致;
    子类中重写的方法的访问权限,不能低于父类中同名方法的访问权限;
    父类方法权限为public,子类同名方法权限只能是public;
    父类方法权限为protected,子类同名方法权限可以是protected和public;
    父类方法权限为private,子类无法继承,也无法重写。
    注意:对于重写构造方法,就比较特殊,就没有形参个数的要求。
<?php
header('Content-Type: text/html; charset=utf-8');
//实例:类的三大特性

//定义一个基础商品类(最顶层)
//基础类是为了继承,不能直接创建对象
class Shop
{
    //私有的商品属性
    private $name;    //商品名称
    private $price;    //商品价格

    //受保护的构造方法
    protected function __construct($name2,$price2)
    {
        $this->name = $name2;
        $this->price = $price2;
    }

    //受保护的显示商品方法
    protected function showInfo()
    {
        $str = "商品名称:{$this->name}";
        $str .= "<br>商品价格:{$this->price}";
        return $str;
    }
}

//创建手机类,并继承商品类
class Mobile extends Shop
{
    //私有的手机属性
    private $pinpai;    //手机品牌
    private $city;        //手机产地

    //重写父类的构造方法
    public function __construct($name2,$price2,$pinpai2,$city2)
    {
        //调用父类的构造方法
        parent::__construct($name2,$price2);
        $this->pinpai = $pinpai2;
        $this->city   = $city2;
    }

    //重写父类的showInfo()方法
    public function showInfo()
    {
        $str = parent::showInfo();
        $str .= "<br>手机品牌:{$this->pinpai}";
        $str .= "<br>手机产地:{$this->city}";
        return $str;
    }
}

//创建图书类,并继承商品类
class Book extends Shop
{
    //私有的图书属性
    private $author;    //作者
    private $publish;    //出版社

    //重写父类的构造方法
    public function __construct($name2,$price2,$author2,$publish2)
    {
        //调用父类的构造方法
        parent::__construct($name2,$price2);
        $this->author = $author2;
        $this->publish= $publish2;
    }

    //重写父类的showInfo()方法
    public function showInfo()
    {
        $str = parent::showInfo();
        $str .= "<br>作者:{$this->author}";
        $str .= "<br>出版社:{$this->publish}";
        return $str;
    }
}

//创建手机类对象
$obj1 = new Mobile('苹果X',8888,'苹果','天津市');
echo $obj1->showInfo();
echo "<hr>";
//创建图书类对象
$obj2 = new Book('PHP从入门到放弃',199.00,'武大郎','武大烧饼铺');
echo $obj2->showInfo();
demo

序列化

<?php
//数组变量序列化
$arr = array(
        'db_host' => 'localhost',
        'db_user' => 'root',
        'db_pass' => 'root',
        'db_name' => 'itcast',
    );
//序列化:将变量转成可保存的字符串
$str = serialize($arr);
//将序列化字符串,保存到记事本
file_put_contents('./1.txt',$str);
数组序列化
<?php
//反序列化:序列化字符串,还原成原始变量
//读取记事本的数据
$str = file_get_contents('./1.txt');
//将序列化字符串,还原成变量
$arr = unserialize($str);
//打印变量
print_r($arr);
数组反序列化

 

<?php
//定义一个数据库工具类
class Db
{
    //私有的数据库配置信息
    private $db_host; //主机名
    private $db_user; //用户名
    private $db_pass; //密码
    private $db_name; //数据库名
    private $charset; //字符集
    private $link; //连接对象

    //公共的构造方法:数据库对象初始化
    public function __construct($config=array())
    {
        $this->db_host = $config['db_host'];
        $this->db_user = $config['db_user'];
        $this->db_pass = $config['db_pass'];
        $this->db_name = $config['db_name'];
        $this->charset = $config['charset'];
        //一个方法只做一件事
        $this->connectDb(); //连接MySQL服务器
        $this->selectDb(); //选择数据库
        $this->setCharset(); //设置字符集
    }

    //私有的连接MySQL服务器方法
    private function connectDb()
    {
        if(!$this->link = @mysqli_connect($this->db_host, $this->db_user, $this->db_pass))
        {
            echo "连接MySQL服务器失败!";
            die();
        }
    }

    //私有的选择数据库的方法
    private function selectDb()
    {
        if(!mysqli_select_db($this->link, $this->db_name))
        {
            echo "选择数据库{$this->db_name}失败!";
            die();
        }
    }

    //私有的设置字符集
    private function setCharset()
    {
        mysqli_set_charset($this->link, $this->charset);
    }

    //当对象序列化时,魔术方法__sleep()会自动调用
    //在__sleep()中工作:清理不需要的属性
    public function __sleep()
    {
        //返回要序列化的对象属性的数组
        return array('db_host','db_user','db_pass','db_name','charset');
    }
}

//创建数据库类的对象
$arr = array(
        'db_host' => 'localhost',
        'db_user' => 'root',
        'db_pass' => 'root',
        'db_name' => 'itcast',
        'charset' => 'utf8'
    );
$db = new Db($arr);
//将数据库对象序列化
$str = serialize($db);
//将对象序列化字符串保存到记事本
file_put_contents('./2.txt',$str);
对象序列化
<?php

//读取记事本的对象序列化字符串
$str = file_get_contents('./2.txt');
//对象反序列化
$db = unserialize($str);
//打印$db对象
var_dump($db);
对象反序列化

类的动态加载

自动载入主要是省去了一个个类去 include 的繁琐,在 new 时或者继承类时动态的去检查并 include 相应的 class 文件。 

示例一

<?php

class MyLoader
{
    public static function l($a)
    {
        include 'myclassfolder/'.$a.'.class.php';
    }
}
//['MyLoader','l']
//spl_autoload_register 第一个参数以数组方式传入
spl_autoload_register(['MyLoader','l'],true,true);

class A extends B
{
    
}
index.php
<?php

class B
{
    
}
myclassfolder/B.class.php

示例二

<?php

class ClassAutoloader {
    public static function loader($className)
    {
        $file = $className . ".class.php";
        
        if(is_file($file))
        {
            echo 'Trying to load ', $className, ' via ', __METHOD__, "()\n";
            require_once( $file );
        }
        else
        {
            echo 'File ', $file, " is not found!\n";
        }
    }

    public static function register($autoLoader = '')
    {
        spl_autoload_register($autoLoader ?: array('ClassAutoloader', 'loader'), true, true);
    }
}

ClassAutoloader::register();

$obj = new printit();
$obj->doPrint();

?>
index.php
<?php 

class PRINTIT { 

 function doPrint() {
  echo "Hello, it's PRINTIT! \n";
 }
}
?> 
printit.class.php

命名空间

<?php
namespace MySapce{
    function test()
    {
        echo 'test1';
    }
    
    
}

namespace MySapce2{
    function test()
    {
        echo 'test2';
    }
    test();
}
demo01
<?php
namespace A;
function time(){
    echo 'my time function <br>';
}



namespace B;
function time(){
    echo 'my space B time function <br>';
}


time();// namespace B time()
\A\time();// namespace A time()
\B\time();// namespace B time()
echo \time(); //    \全局空间
demo02
<?php
namespace A\B;
class MyClass
{
    public function __construct()
    {
        echo '空间A\B 中的类 实例化了 <br>';
    }
}

namespace A;
class MyClass
{
    public function __construct()
    {
        echo '空间A 中的类 实例化了 <br>';
    }
}

$obj = new MyClass();// 非限定名称
$obj = new \A\B\MyClass();// 完全限定名称
$obj = new \A\MyClass();// 完全限定名称
$obj = new B\MyClass();//限定名称
demo03
<?php
namespace A\B;
class MyClass
{
    public function __construct()
    {
        echo '空间A\B 中的类 实例化了 <br>';
    }
}

echo __NAMESPACE__;
echo '<hr>';

namespace A;
class MyClass
{
    public function __construct()
    {
        echo '空间A 中的类 实例化了 <br>';
    }
}

echo __NAMESPACE__;
demo04
<?php
namespace A\B;
class MyClass
{
    public function __construct()
    {
        echo '空间A\B 中的类 实例化了 <br>';
    }
}

echo __NAMESPACE__;
echo '<hr>';

include '5_2.php';

echo __NAMESPACE__;
echo '<hr>';
$obj = new MyClass();
$obj = new C\MyClass();
$obj = new \A\B\C\MyClass();
demo05
<?php

namespace A\B\C;
class MyClass
{
    public function __construct()
    {
        echo '空间A\B\C 中的类 实例化了 <br>';
    }
}
demo06

使用use的目的

在命名空间字符串过长时,使用use可以相应的缩短命名空间。

//name.php

namespace animal\dog;

class Life{
    function __construct(){
            echo 'dog life!';
        }
}

namespace animal\cat;

class Life{
    function __construct(){
            echo 'cat life!';
        }
}

new Life();  //按照代码执行顺序,这里默认animal\cat这个命名空间
new \animal\dog\Life();  //A

use animal\dog;  //a
new dog\Life();  //B

use animal\dog as d;  //b
new d\Life();

 

 

  

 

 

  

  

 

  

  

 

 

 

 

 

posted @ 2019-10-09 16:23  沐风先生  阅读(119)  评论(0编辑  收藏  举报