php start 四

1.2 自动加载类

在项目开发中,因为一个文件中只能写一个类,并且执行过程中会有很多类的参与,如果一个一个的加载很麻烦,所以就需要一个机制实现在PHP执行过程中自动加载需要的类。

1.2.1 书写类的规则

1.一个文件中只能放一个类(必须)
2.文件名和类名同名(必须)
3.类文件以.class.php结尾(不是必须)

1.2.2 手动加载类

1、创建Goods.class.php页面

<?php
//商品类
abstract class Goods {
	protected $name;
	final public function setName($name){
		$this->name=$name;
	}
	public abstract function getName();
}

2、创建Book.class.php页面

<?php 
//书籍类
class Book extends Goods{
	public function getName(){
		echo "《{$this->name}》<br>";
	}
}

3、创建Phone.class.php页面

<?php
//电话类
class Phone extends Goods{
	public function getName(){
		echo $this->name,'<br>';
	}
}

4、在PHP页面上加载类文件

<?php
//测试
require './Goods.class.php';//手动加载类文件
require './Book.class.php';//手动加载类文件
require './Phone.class.php';//手动加载类文件
$book=new Book();
$book->setName('面向对象编程');
$phone=new Phone();
$phone->setName('苹果6s');
$book->getName();// 面向对象编程
$phone->getName();//苹果6s

运行结果

面向对象编程
苹果6s

1.2.3 自动加载类 方法一:__autoload()函数

当缺少类的时候自动的调用__autoload()函数,并且将缺少的类名作为参数传递给__autoload().

<?php
/*
*作用:自动加载类
*@params $class_name string 缺少的类名
*/
function __autoload($class_name){
	require "./{$class_name}.class.php";
}
//测试
$book=new Book();
$book->setName('面向对象编程');
$phone=new Phone();
$phone->setName('苹果6s');
$book->getName();// 面向对象编程
$phone->getName();//苹果6s

注意:__autoload()函数在PHP7.2以后都不支持了

1.2.4 自动加载类 方法二:spl_autoload_register()

注册__autoload函数

<?php
//方法一:
/*
//加载类函数
function loadClass($class_name){
	require './{$class_name}.class.php';
}
//注册加载类函数
spl_autoload_register('loadClass');
*/
//方法二:
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
//测试
$book=new Book();
$book->setName('面向对象编程');
$phone=new Phone();
$phone->setName('苹果6s');
$book->getName();// 面向对象编程
$phone->getName();//苹果6s

1、spl_autoload_register()可以注册多个自动加载函数

function load1($class){
	require "./{$class}.class.php";
}
function load2($class){
	require "./{$class}.php";
}
function load3($class){
	require "./{$class}.fun.php";
}
spl_autoload_register('load1');
spl_autoload_register('load2');
spl_autoload_register('load3');

2、PHP5.1以后就开始支持此函数。

1.2.5 类文件存储不规则的加载方法

将类名和文件地址做一个映射,组成一个关联数组。

代码如下

spl_autoload_register(function($class_name){
	//类名和文件地址映射成一个关联数组
	$map=array(
		'Goods'=>'./aa/Goods.class.php',
		'Book'=> './bb/Book.class.php',
		'Phone'=> './cc/Phone.class.php',
	);
	//在映射数组中找到就引入
	if(isset($map[$class_name]))
		require $map[$class_name];
});
//测试
$book=new Book();
$book->setName('面向对象编程');
$phone=new Phone();
$phone->setName('苹果6s');
$book->getName();// 面向对象编程
$phone->getName();//苹果6s

在项目中,绝大部分都是规则存储的,不规则的比较少。

1.3 clone和_clone()

思考:创建对象的方式有哪些?

方法一:实例化
方法二:克隆

例题

<?php
class Student{
	//执行clone指令的时候自动执行
	public function __clone(){
		echo '正在克隆对象<br>';
	}
}
$stu1=new Student;
$stu2=clone $stu1;//克隆对象
var_dump($stu1,$stu2);// object(Student)#1 (0){} object(Student)#2 (0) {}

小结:
1、clone是创建对象的方法之一
2、当执行clone指令的时候,会自动的调用__clone()方法

1.4 设计模式

1.4.1 单例模式

一个类只能有一个对象
应用场景:多次请求数据库只需要一个连接对象。
实现:三私一公

1、私有的静态属性用来保存对象的单例
2、私有的构造方法用来阻止在类的外部实例化
3、私有的__clone阻止在类的外部clone对象
4、公有的静态方法用来获取对象的单例

代码

<?php
//三私一公
class DB{
	//静态的属性用来保存对象的单例
	private static $instance;
	//私有的构造方法阻止在类的外部实例化
	private function __construct(){
	
	}
	//私有的__clone() 阻止在类的外部clone对象
	private function __clone(){

	}
	public static function getInstance(){
		//保存的值不属于DB类的类型就实例化
		if(!self::$instance instanceof self)
			self::$instance=new self();
		return self::instance;
	}
}
//测试
$db1=DB::getInstance();
$db2=DB::getInstance();
$db3=clone $db2;//报错
var_dump($db1,$db2);//object(DB)#1(0){} object(DB)#1(0){}

1.4.2 工厂模式

特点:传递不同的参数获取不同的对象

<?php
class ProductsA{}
class ProductsB{}
//工厂模式
class ProductsFactory{
	public function create($num){
		switch($num){
			case 1:
				return new ProductsA;
			case 2:
				return new ProductsB;
			default:
				return null;
		}
	}
}
//测试
$factory=new ProductsFactory();
$obj1=$factory->create(1);
$obj2=$factory->create(2);
var_dump($obj1,$obj2);//object(ProductsA) #2 (0) {} object(ProductsB) #3 (0) {} 

1.4.3 策略模式

特点:传递不同的参数调用不同的策略(方法)

<?php
class Walk {
	public function way(){
		echo '走着去<br>';
	}
}
class Bus{
	public function way(){
		echo '坐车去<br>';
	}
}
//策略模式
class Student{
	public function play($obj){
		$obj->way();
	}
}
//测试
$stu=new Student;
$stu->play(new Walk());//走着去
$stu->play(new Bus());//坐车去

1.5 序列化与反序列化

在PHP中,数组和对象无法保存,如果需要保存就要将数组或对象转换成一个序列。
序列化:将数组或对象转换成一个序列(serialize)
反序列化:将序列化的字符串转换成数组或对象。(unserialize)

1.5.1 数组的序列化与反序列化

<?php
//数组的序列化

$stu=['tom','berry','ketty'];
$str=serialize($stu);//序列化
file_put_contents('./stu.txt',$str);

//数组的反序列化
$str=file_get_contents('./stu.txt');
$stu=unserialize($str);//反序列化
print_r($stu);//Array([0]=>tom [1]=>berry [2]=>ketty)

1.5.2 对象的序列化与反序列化

注意:对象的反序列化需要有类的参与,如果没有类在反序列化时候无法确定类

代码

<?php
class Student{
	public $name;
	protected $sex;
	private $add;
	public function __construct($name,$sex,$add){
		$this->name=$name;
		$this->sex=$sex;
		$this->add=$add;
	}
}
//测试
$stu=new Student('tom','男','北京');
//序列化
$str=serialize($stu);
file_put_contents('./stu.txt',$str);

//反序列化,对象的反序列化必须要有类的参与
$str=file_get_contents('./stu.txt');
$stu=unserialize($str);
echo '<pre>';
var_dump($stu);

1.6 魔术方法(某些情况下自动调用的方法)

已经学习的魔术方法

__construct() //构造函数 实例化的时候自动调用
__destruct() //析构函数 销毁的时候自动调用
__clone() //克隆对象

1.6.1 __tostring()、__invoke()

__tostring():将对象当成字符串使用的时候自动调用
__invoke:将对象当成函数使用的时候自动调用

<?php
class Student{
	//把对象当成字符串使用的时候自动执行
	public function __tostring(){
		return '这是一个对象,不是字符串<br>';
	}
	//把对象当成函数使用的时候自动执行
	public function __invoke(){
		echo '这是一个对象,不是函数<br>';
	}
}
$stu=new Student;
echo $stu;//当成字符串使用
$stu();//当成函数使用

1.6.2 __set()、__get()、__isset()、__unset()

__set($k,$v):给无法访问的属性赋值的时候自动执行
__get($k):获取无法访问的属性值的时候自动调用
__isset($k):判断无法访问的属性是否存在自动调用
__unset($k):销毁无法访问的属性的时候自动执行
<?php
class Student{
	private $name;
	private $sex;
	private $age;
	//给无法访问的属性赋值的时候自动执行
	public function __set($k,$v){
		$this->$k=$v;
	}
	//获取无法访问的属性值的时候自动调用
	public function __get($k){
		return $this->$k;
	}
	//判断无法访问的属性是否存在自动调用
	public function __isset($k){
		return isset($this->$k);
	}
	//销毁无法访问的属性的时候自动执行
	public function __unset($k){
		 unset($this->$k);
	}
}

//测试
$stu=new Student;
$stu->name='tom';
$stu->sex='男';
$stu->age=22;
print_r($stu);//Student Object([name:Student:private]=>tom [sex:Student:private]=>男 [age:Student:private]=>22)
//echo $stu->name;
var_dump(isset($stu->name));
unset($stu->age);
print_r($stu);

应用:设置读写属性

<?php
class Student{
	private $name;//读写属性
	private $add='中国'; //只读属性
	private $age;  //只写属性
	public function __set($k,$v){
		if(in_array($k,array('name','age')))
			$this->$k=$v;
		else
			echo "{$k}属性是只读属性<br>";
	}
	public function __get($k){
		if(in_array($k,array('name','add')))
			return $this->$k;
		else 
			echo "{$k}是只写属性<br>";
	}
}
//测试
$stu=new Student;
$stu->name='tom';
echo '姓名'.$stu->name,'<br>';
echo '地址'.$stu->add,'<br>';
echo $stu->age;

1.6.3 __call()、__callstatic()

__call():调用无法访问的方法时自动执行
__callstatic():调用无法访问的静态属性方法时自动执行

例题:

<?php
class Student{
	/*
	*作用:调用无法访问的方法时自动执行
	*@param $fn_name string 方法名
	*@param $fn_args array 参数数组
	*/
	public function __call($fn_name,$fn_args){
		echo "{$fn_name}不存在<br>";
	}
	//调用无法访问的静态方法时自动执行
	public static function __callstatic($fn_name,$fn_args){
		echo "{$fn_name}静态方法不存在<br>";
	}
}
$stu=new Student;
$stu->show(10,20);//show不存在

Student::show();//show静态方法不存在

1.6.4 __sleep()、__wakeup()

<?php
class Student{
	private $name;
	private $sex;
	private $add='中国';
	public function __construct($name,$sex){
		$this->name=$name;
		$this->sex=$sex;
	}
	/**
	*序列化的时候自动执行
	*@return array 序列化的字段名
	*/
	public function __sleep(){
		return array('name','sex');
	}
	//反序列化的时候自动调用
	public function __wakeup(){
		$this->type="学生";
	}
}
//测试
$stu=new Student('tom','男');
$str=serialize($stu);//序列化
$stu=serialize($str);//反序列化
print_r($stu);

1.7 模拟方法重载

通过魔术方法模拟方法重载

class Math {
	public function __call($fn_name,$fn_args){
		$num=0;
		foreach($fn_args as $v){
			$num+=$v;
		}
		echo implode(',',$fn_args).'的和是:'.$num,'<br>';
	}
}
//利用魔术方法模拟重载
$namth=new Math();
$math->call(10,20);
$math->call(10,20,30);
$math->call(10,20,30,40);

1.8 遍历对象

通过foreach遍历对象

class Student{
	public $name='tom';
	protected $sex='男';
	private $age=22;
	
	public function show(){
		foreach($this as $k=>$v){
			echo "{$k}-{$v}<br>";
		}
	}
}
//测试
$stu=new Student;
foreach($stu as $k=>$v){
	echo "{$k}-{$v}<br>";
}
echo '<hr>';
$stu->show();
/*
*结果
*name-tom
*--------------------------
*name-tom
*sex-男
*age-22
*/
//结论:遍历到当前位置所能访问到的属性

1.9 封装MySQL单例

1.9.1 分析

1、实现单例
2、连接数据库
3、对数据进行操作

1.9.2 步骤

第一步:实现单例
第二步:初始化参数
第三步:连接数据库
第四步:操作数据库

1.9.3 代码实现

第一步:实现单例

<?php
class MySQLDB{
	private static $instance;
	private function __construct(){
	
	}
	private function __clone(){
	
	}
	public function getInstance(){
		if(!self::$instance instanceof self)
			self::$instance=new self();
		return self::$instance;
	}
}
//测试
$db=MySQLDB::getInstance();
var_dump($db);

注意:A instance B,表示A是否是B的类型,返回bool值

第二步:初始化参数

//封装MySQL单例
class MySQLDB{
	private $host;//主机地址
	private $port;//端口号
	private $user;//用户名
	private $pwd;//密码
	private $dbname;//数据库名
	private $charset;//字符集
	private $link;//连接对象
	private static $instance;
	private function __construct($param){
		$this->initParam($param);
	}
	private function __clone(){
	
	}
	//获取单例
	public function getInstance($param=array()){
		if(!self::$instance instanceof self)
			self::$instance=new self($param);
		return self::$instance;
	}
	//初始化参数
	private function initParam($param){
		$this->host=$param['host']??'127.0.0.1';
		$this->port=$param['port']??'3306';
		$this->user=$param['user']??'';
		$this->pwd=$param['pwd']??'';
		$this->dbname=$param['dbname']??'';
		$this->charset=$param['charset']??'utf8';
	}
}
//测试
//配置参数
$param=array(
	'host'=>'127.0.0.1',
	'user'=>'root',
	'pwd'=>'root'
)
//获取单例
$db=MySQLDB::getInstance($param);
var_dump($db);

第三步:连接数据库

//封装MySQL单例
class MySQLDB{
	private $host;//主机地址
	private $port;//端口号
	private $user;//用户名
	private $pwd;//密码
	private $dbname;//数据库名
	private $charset;//字符集
	private $link;//连接对象
	private static $instance;
	private function __construct($param){
		$this->initParam($param);
		$this->initConnect()
	}
	private function __clone(){
	
	}
	//获取单例
	public function getInstance($param=array()){
		if(!self::$instance instanceof self)
			self::$instance=new self($param);
		return self::$instance;
	}
	//初始化参数
	private function initParam($param){
		$this->host=$param['host']??'127.0.0.1';
		$this->port=$param['port']??'3306';
		$this->user=$param['user']??'';
		$this->pwd=$param['pwd']??'';
		$this->dbname=$param['dbname']??'';
		$this->charset=$param['charset']??'utf8';
	}
	//连接数据库
	private function initConnect(){
		$this->link=@mysqli_connect($this->host,$this->user,$this->pwd,$this->dbname);
		if(mysqli_connect_error()){
			echo '数据库连接失败<br>';
			echo '错误信息:'.mysqli_connect_error(),'<br>';
			echo '错误码:'.mysqli_connect_errno(),'<br>';
			exit;
		}
		mysqli_set_charset($this->$link,$this->charset);
	}
}
//测试
//配置参数
$param=array(
	'user'=>'root',
	'pwd'=>'root',
	'dbname'=>'data'
)
//获取单例
$db=MySQLDB::getInstance($param);
var_dump($db);

第四步:数据库操作的功能
1、执行数据操作语句(增、删、改)
2、执行数据查询语句
a)返回二维数组
b)返回一维数组
c)返回一行一列
代码

//封装MySQL单例
class MySQLDB{
	private $host;//主机地址
	private $port;//端口号
	private $user;//用户名
	private $pwd;//密码
	private $dbname;//数据库名
	private $charset;//字符集
	private $link;//连接对象
	private static $instance;
	private function __construct($param){
		$this->initParam($param);
		$this->initConnect()
	}
	private function __clone(){
	
	}
	//获取单例
	public function getInstance($param=array()){
		if(!self::$instance instanceof self)
			self::$instance=new self($param);
		return self::$instance;
	}
	//初始化参数
	private function initParam($param){
		$this->host=$param['host']??'127.0.0.1';
		$this->port=$param['port']??'3306';
		$this->user=$param['user']??'';
		$this->pwd=$param['pwd']??'';
		$this->dbname=$param['dbname']??'';
		$this->charset=$param['charset']??'utf8';
	}
	//连接数据库
	private function initConnect(){
		$this->link=@mysqli_connect($this->host,$this->user,$this->pwd,$this->dbname);
		if(mysqli_connect_error()){
			echo '数据库连接失败<br>';
			echo '错误信息:'.mysqli_connect_error(),'<br>';
			echo '错误码:'.mysqli_connect_errno(),'<br>';
			exit;
		}
		mysqli_set_charset($this->$link,$this->charset);
	}
	//执行数据库的增、删、改、查
	private function execute($sql){
		if(!$rs=mysqli_query($this->link,$sql)){
			echo 'SQL语句执行失败<br>';
			echo '错误信息:'.mysqli_error($this->link),'<br>';
			echo '错误码:'.mysqli_errno($this->link),'<br>';
			echo '错误的SQL语句:'.$sql,'<br>';
			exit;
		}
		return $rs;
	}
	/*
	*执行增、删、改
	*@return bool 成功返回true,失败返回false
	*/
	public function exec($sql){
		$key=substr($sql,0,6);
		if(in_array($key,array('insert','update','delete')))
			return $this->execute($sql);
		else{
			echo '非法访问<br>';
			exit;
		}
	}
	//获取自动增长的编号
	public function getLastInsertId(){
		return mysqli_insert_id($this->link)
	}
	//执行查询语句
	public function query($sql){
		if(substr($sql,0,6)=='select' || substr($sql,0,4)=='show' || sunstr($sql,0,4)=='desc'){
			retuen $this->execute($sql)
		}else{
			echo '非法访问<br>';
			exit;
		}
	}
	/*
	*执行查询语句,返回二维数组
	*@$sql string 查询sql语句
	*@$type string assoc|num|both
	*/
	public function fetchAll($sql,$type='assoc'){
		$rs=$this->query($sql);
		$type=$this->getType($type);
		return mysqli_fetch_all($rs,$type);
	}
	//匹配一维数组
	public function fetchRow($sql,$type='assoc'){
		$list=$this->fetchAll($sql,$type);
		if(!empty($list))
			return $list[0];
		return array();
	}
	//匹配一行一列
	public function fetchColumn($sql){
		$list=$this->fetchRow($sql,'num');
		if(!empty($list))
			return $list[0];
		return null;
	}
	//获取匹配类型
	private function getType($type){
		switch($type){
			case 'num':
				return MYSQL_NUM;
			case 'both':
				return MYSQL_BOTH;
			default:
				return MYSQL_ASSOC;
		}
	}
}
//测试
//配置参数
$param=array(
	'user'=>'root',
	'pwd'=>'root',
	'dbname'=>'data'
)
//获取单例
$db=MySQLDB::getInstance($param);
//更新
$db->exec("update news set title='青草' where id=2");
/插入
if($db->exec("insert into news values (null,'aa','bb',unix_timestamp())"))
	echo '编号是:'.$db->getLastInsertId();

//查询
//$list=$db->fetchAll('select * from news','both');
$list=$db->fetchRow('select * from news where id=2','aa');
echo '<pre>';
var_dump($list);

小结:
1、instanceof用来判断对象是否属于某个类
2、参数必须从外部传递到内部,不能写死到类的内部
3、为了保证代码的可重用性,一个方法只实现一个功能,所以初始化参数和连接数据库分到两个方法中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值