PHP-OOP1( 万物皆对象!)- 编程思想,类,属性,方法
一、编程思想 :计算机解决实际问题的一种思维方式。
PHP 是同时支持面向过程和面向对象两种编程思想的语言。
面向对象的核心思想是: 不仅仅简单的将某些功能进行封装(封装成函数),更是对调用该功能的主体进行封装,实现某个
主体拥有多个功能, 在使用的过程中,先得到对应的主体,再使用主体去实现相关的功能!
面向过程---自顶向下,逐步细化
面向对象---在编程的时候尽可能的模拟现实世界!
面向过程写代码, 需要实现哪些功能以及如何去实现---1 调用系统函数,2 用户自定义函数,3 流程控制(整体调度)
面向对象写代码,首先想到的是应该有什么样的主体去完成什么样的功能,再把该主体的属性和功能进行封装,再去实现该主体的功能!
面向对象与面向过程的区别
- 都可以实现代码重用和模块化编程,面向对象的模块化更深,数据更封闭,也更安全
- 面向对象的思维方式更加贴近于现实生活,也容易解决大型复杂的业务逻辑
- 从前期开发的角度看,面向对象比面向过程更复杂,但是,从维护和扩展功能的角度来看,面向对象要远比面向过程要简单!
二、1.面向对象三阶段OOA,OOD,OOP----------OOP : 面向对象编程
对象是采用属性( property )来 保存 数据!
对象是采用方法( method )来 管理 数据!
对象是由类实例化而来的!
强调: 无论在哪里,访问成员的属性和方法都要先找到其对象才可以!
二、2.1类的定义 类就是具有相同或相似的特征特性的一组事物的一个通用的名称!
2.2类的组成 定义一个类,其实就是定义三种类成员 : 定义属性 (变量), 定义方法 (函数), 定义类常量 (常量)
2.3类的实例化 语法形式是: new 类名 ;
几点需要注意的地方:
1 .属性和方法都 需要 进行 声明 才可以使用!(采用访问控制修饰限定符来声明public,proteced,private)
2. public可以用 var 来 代替 ,只是对低版本的一种兼容!
3 . 方法 的前面可以省略掉访问控制修饰限定符,默认的就是 public
4 . 在定义类的时候,属性 的值默认是 NULL 型,但是如果给属性赋 上一个初始值 ,必须 是“直接值 ”,不能是表达式计算之后的值!
//例:定义一个类
Class Student{
public $stu_name;
public $stu_money=30000;
public function payMoney(){
echo $this->stu_name, '刚交完' ,$this->stu_money, '学费,要好好学习';
} //this调用当前对象
}
$stu=new Student; //类的实例化
$stu->stu_name="鸣人"; //访问对象的属性
$stu->payMoney(); //调用对象的方法(方法必须有对象来调用才能执行,否则找不到方法)
//执行结果: 鸣人刚交完30000学费,要好好学习
3.类成员的访问 使 用箭头 -> 实现对象对对象成员的访问!
属性不能在方法内直接访问,需要找到其对象才能访问,典型的做法就是,在方法内使用 this 来代替 当前对象 的名称!
调用方法时,必须先通过对象找到所属类,然后再找到相应方法
打印实例时,为什么只能打印出属性而打印不出方法?
方法属于公共代码,存储在用户代码区,由类管理。而属性属于每个实例,由实例管理,3空间如下
类---------类空间---------类常量
类---------用户代码区-----方法
对象-------对象空间-------属性
第一步:找到所有的实体
第二步:定义相关的类
第三步:实例化对象并初始化
第四步:执行相应的功能
在实例化一个对象的时候, PHP 会 自动的 调用一个名字叫作 __construct() 的方法,该方法由于专门负责对新对象进行初始化,称之为“构造方法”!
在实例化一个对象的时候,顺便在类名的后面增加一些用括号括起来的参数列表(可以理解为构造方法的实参)
创建初始化方法和构造方法
Class Student{
public $stu_name;
public $stu_money;
public function payMoney(){
echo $this->stu_name,'刚交完',$this->stu_money,'学费,要好好学习';
}
// public function init($m,$n){ //创建一个专门对对象的属性初始化的方法
// $this->stu_name=$n;
// $this->stu_money=$m;
// }
public function __construct($m,$n){ //构造方法
$this->stu_name=$n;
$this->stu_money=$m;
}
}
// $stu1=new Student;//类的实例化
// $stu1->init(30000,"鸣人");
// $stu1->payMoney();//调用对象的方法
echo " ";
$stu2=new Student(50000,"佐助");//类的实例化
$stu2->payMoney();//调用对象的方法
可兼容旧版本的构造方法书写方式:
public function __construct($n,$a,$m){
$this->Student($n,$a,$m);
}
public function Student($n,$a,$m) {
$this->stu_name = $n;
$this->stu_age = $a;
$this->stu_money = $m;
}
6.析构方法
主要的作用就是用于释放对象所占用的额外的资源!而不是对象本身!
析构方法的名字叫作 __destruct(), 注意,里面不能有任何的参数!在对象消失之前调用。 因此还能使用 $this !
对象消失的几种情况
明确的使用 unset 函数销毁一个变量
脚本运行结束之后,也会自动销毁
改变对象变量的值,也会自动销毁
常见的有一种删除对象的方法: $stu1 = NULL;
与构造方法是一对,构造方法是在一个对象“出生”的时候自动调用的,而析构方法是在一个对象“消失”的时候由系统自动调用的!
PHP-OOP2(对象传值、克隆、静态,类常量,自动加载 )
一、对象的传值
1.为什么对象之间,不管使用值传递还是引用传递, 效果都是引用传递的效果?
本质:对象的变量名并不是直接引用对象的内存空间,而 是引用对象的内部编号 。而对象的值传递或者引用传递,
其实复制的都是这个编号,所以效果都是引用传递的效果。
2. 对象间的复制,无法开辟一个新的对象空间,有时候,也称之为 “浅复制” !例 $stu2=$stu1;
3.那么,如何 使用一个已有的对象,得到一个全新的对象呢 (单独开辟新的内存空间)-- 需要使用对象的克隆!
二、对象的克隆(生成对象的两种方法之二)
1.所谓的克隆 ,不是通过类的实例化得到一个新对象,而是通过一个已有的对象得到一个新对象 !
2.语法形式 新对象 = clone 已有对象------例:$stu2 = clone $stu1;
新旧对象之间,具有相同属性名和值 ,但是对象的内存空间不同 (内部编号不同)
注意:克隆不是实例化,所以不需要执行构造方法!
3.使用instanceof 运算符 判断某个对象是否是由某个类实例化而来的!
形式为: 对象变量 instanceof 类名---结果: 返回一个布尔值!例 var_dump($stu2 instanceof Student); //bool(true)
4. __clone() 方法 也是属于魔术方法!
触发情况:__当一个对象被克隆的时候自动调用该魔术方法!功能:对克隆出来的新对象进行相关的初始化!
三、MySQLDB 类初步
一般类文件的命名方式为: 类名 .class.php--------例:MySQLDB.class.php
1.设置属性, 实例化的时候对属性进行初始化
2. 完成对数据库的连接三步曲(连接数据库,选择默认数据库,设置默认字符集)(构造方法)
3. 销毁该对象,释放对象所占用的数据库连接资源(析构方法)
四、静态成员
(1)静态属性
1、用来定义属于类的属性。静态属性属于类,所以只占一块内存空间,每个对象都可以引用这块内存空间。
静态属性的值对于各实例是一样的,如果改变,则都改变。通常用来存储属于该类的属性。
2、 声明:访问控制修饰符 static 属性名-----例: public static $total = 0; //声明一个$total的静态属性
3、 访问:静态属性属于类,所以应该用类名来调用。也可以使用实例来调用
1.在类外访问
使用类名来访问 类名 :: 属性名---例:echo Student::$stu_num; //注意这有$
通过实例来访问 例: $wangwang = new Dog; echo $wangwang::$averageLife;
2.在类内访问
使用类名来访问 类名 :: 属性名---例:echo Student::$stu_num;
通过self关键字调用 例:echo self::$student;//注意self类外不能使用
(2)静态方法: 所有对象所共享的方法!
1、声明:访问控制修饰符 static 方法名
2、 访问: 类名::方法名
静态方法的访问和静态属性的访问方式相同。 在类外、 类内访问同 静态属性访问。
3、静态方法和非静态方法的区别
非静态方法: 是指各个对象“独自”占用的方法(尽管也只有一份)
无论采用什么方式调用静态方法,都不可以使用 $this! 建议用self
无论是静态方法,还是非静态方法,类和对象都可以调用! 但是,我们以后编程的标准只有一个:
那就是类调用静态成员!对象调用非静态成员!切记切记!!!
class Student{
public static $stu_age;
public function set_age($age){
if (is_int($age)&&$age>=0 &&$age<=150) {
self::$stu_age=$age;//这里设置静态变量时不能用$this,切记
} else {
echo "非法的年龄信息";
return false;
}
}
}
$stu=new Student;
$stu->set_age(20);//调用类中公开的接口
echo $stu::$stu_age; //10,调用并获取静态变量
var_dump($stu);//object(Student)#1 (0) { }
五、类常量
就是指在一个类中定义的常量,和普通的常量没有什么本质的区别,只是类常量需要先找到类才能访问常量!
声明语法: const 常量名 = 常量值 ;例const SCHOOL="whereit";
访问: 类名 :: 常量名----- 例:echo Student::SCHOOL; 在一个类的内部,类名也可以使用 self 来代替!
注意:类中所有的成员
一共有 5 种: 非静态属性, 非静态方法,静态 方法, 静态属性, 类常量,
只有非静态属性保存在对象空间里面,其他都在类的用户代码区 和 类空间 。
六、 手动加载类文件include './Student.class.php';
在实际的项目中,如果一个类在多个脚本文件都需要使用的话,可以将这个类 文件名字为: 类名 .class.php,
并 单独的放到一个文件内,当需要的时候,将文件加载进来即可!
方法:直接使用include_once() 将所需的类文件包含进来,或 将所有的类文件导入一个文件里面,然后需要的时候将这个文件导入即可。
七、类文件的自动加载
php加载文件方式:
1、include,include_once,requice,requice_one常规加载
2、__autoload()
3、spl_autoload_register()
触发情况:当php找不到类文件的时候//注意触发条件,如果本页面内有该类名,无法加载
function __autoload($class_name){
if (is_file("./$class_name.class.php")) {
include_once("./$class_name.class.php");
}else{
die("./$class_name.class.php不存在");
}
}
$stu=new Studet; //本页无Student类,则会自动去Student.class.php中找Student类。
为何要使用自定义的类文件自动加载函数?
因为随着项目的扩展,可能后期会出现多个自动加载函数,这时候就出现了函数的重名问题,因此我们要自己注册 自动加载函数
八-9.1注册其他的自动加载函数
实现步骤: 第一步:定义一个可以加载类文件的普通函数
第二步:使用spl_autoload_register(函数名)来实现注册 spl_autoload_register(‘ 函数名 ’);
注意:
1.注册一定要发生在需要某个类之前
2. 可以注册多个,在需要的类文件载入成功之前,系统会依次调用
3. 一旦注册成功,系统默认的__autoload就会失效,如果想继续使用,就需要像注册其他普通函数一样重新注册
function f1($class_name){
if (is_file("./$class_name.class.php")) {
include_once("./$class_name.class.php");
}else{
die("./$class_name.class.php不存在");
}
}
spl_autoload_register("f1");
$obj=new A;//本页无A类,则会自动去A.class.php中找A类。
八-9.2 注册自动加载方法
在面向对象的编程风格中,我们一般会将用户自定义的自动加载函数封装 到一个类中!
语法形式1为spl_autoload_register(array(类名,方法名))spl_autoload_register(array('Common','hhh'));
语法形式2为spl_autoload_register('类名::方法名') spl_autoload_register('Common::hhh');
先实例化对象,再注册。语法形式为spl_autoload_register(array(对象,'方法名'))
$stu=new Common; spl_autoload_register(array($stu,'hhh'));
class Common{
//public static function hhh($class_name){
public function hhh($class_name){
if (is_file("./$class_name.class.php")) {
include_once("./$class_name.class.php");
}else{
die("./$class_name.class.php不存在");
}
}
}
// spl_autoload_register(array('Common','hhh')); //静态方法注册
$stu=new Common; //1实例化方法对象并注册该方法
spl_autoload_register(array($stu,'hhh'));//非静态方法注册
$obj = new A; //2自动去A.class.php中找A类,这样就可以使用A类中的函数了。
PHP-OOP3(继承、封装、多态,重写、final、 abstract、interface )
一、类的继承 面向对象的三大特性之一:继承性! 利于代码的扩展和重用
伟大的程序员都懒!都要在两个字上下功夫: ” 简 ” , ” 易 ” !
继承: 一个类从另外一个已有的类获得其成员特性,就叫作继承!extends
几个概念:派生, 父类(基类)parent、子类(派生类)、扩展、单继承、继承链条
单继承: 在 PHP 中,一个类只能继承自一个其他的类,不同同时继承多个类,单继承也是大多数面向对象语言的特性( C++ 支持多继承)
几点强调
属性和方法都可以被继承
继承的本质,不是把父类中的代码复制到子类的内部,而是通过继承链条 ,找到相应的成员!
class Goods{//定义一个父类Goods
public $goods_id;
public $goods_name;
public $goods_price;
public function showName(){
echo $this->goods_name;
}
}
class Book extends Goods{
public $publisher;
public $author;
}
class Mango extends Book{//继承链条
public $system;
public $pages;
}
$book=new Book;
$mango=new Mango;
var_dump($book,$mango);
$book->goods_name="海贼王";
$book->showName();//输出:海贼王
二、2.1多态
2、在面向对面语言中,多态指的是不同的对象,对同一个消息的不同响应。
3、多态,意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。
4、有继承才有多态。方法的重写可以实现多态。因此父类尽量是抽象类或者接口。
class Bird{// 定义一个Bird类
public $age;// Bird的年龄
public $sex;// Bird的性别
public function chirm(){// 鸟鸣方法
echo "叽叽喳喳... ";
}
public function fly(){
echo "飞呀飞呀... ";
}
}
class Parrot extends Bird{// 鹦鹉类 重写了chirm鸟鸣方法
public function chirm(){
echo "你好你好... ";
}
}
class Ostrich extends Bird{// 鸵鸟类 重写了fly方法
public function fly(){
$this->run();
}
public function run(){
echo "跑啊跑啊... ";
}
}
function fly($obj){// 如果属于鸟类,则让它飞行
if($obj instanceof Bird) $obj->fly();
}
function chirm($obj){// 如果属于鸟类,则让它鸣叫
if($obj instanceof Bird) $obj->chirm();
}
// 不同的对象对同一种方法的不同反应
fly(new Ostrich()); //跑啊跑啊...
fly(new Parrot()); //飞呀飞呀...
chirm(new Ostrich());//叽叽喳喳...
chirm(new Parrot());//你好你好...
2.2重写 override
1、重写也叫作覆盖,就是当子类的成员与父类的成员的名字相同的时候,从父类继承下来的成员会重新定义!
注意: 重写是由继承链决定的,当子类调用一个方法的时候。如果在子类没有找到,就会接着在父类寻找。所以重写并不是真正意义上的覆盖父类方法。
在真实的项目中,一般是可以通过修改方法的名字来避免重写的!
但是,有些方法的名字是固定的,比如:构造方法,析构方法等魔术方法,所以,这种情况,重写不可避免!
2、重写的其他语法
1.如果必须要执行被重写的父类方法,必须在子类的方法中 ,显式的调用父类的同名方法!此时子类方法参数要加上它。
语法-----父类名 :: 父类中的方法名-----例:Goods::_contruct($name);
2.parent 不一定就代表本类的上一级父类,如果父类中没有找到相应的方法,会继续的向更上一级的父类查找!
parent::_contruct($name);---建议使用parent代替
3.当子类重写父类的方法的时候,方法的参数形式(个数),必须与父类保持一致(构造方法除外)
例:$mango=new Mango("尾田","海贼王");
三、3.1封装 面向对象的三大特性之一: 封装性 主要是为了实现程序的单入口 。
3.2访问控制修饰符
1、在 PHP 中,一共有三个访问控制范围的概念:
当前类内: 当前代码所在的类内
继承链类内: 所有在一个继承链上的类内,并且对于链上的任意的一个类,访问的范围是一样
类外: 除了类内,都是类外
所以,访问控制修饰符也一共有三个:
public : 公共的,当前类内,继承链类内和类外都可以被访问到
protected : 受保护的,当前类内以及继承链上的类内可以被访问到(该类或其子类)
private : 私有的,只有当前类内可以被访问到
2、访问控制修饰符的使用原则
尽量的隐藏类的内部实现,仅仅公开一些操作接口!(接口就是对象对外部公开的操作方法)
其他原则
1.当子类重写父类的成员时,子类成员的访问控制权限不应该低于父类的访问控制权限!
若父类:public 子类:只能是public,若父类:protected 子类:可以是protected也可以是pubic
2. 从形式上看,子类可以继承父类的私有成员,但是却无法使用!
3 .私有成员(私有属性和私有方法)都不能被重写,但是子类还是可以定义跟父类私有成员同名的成员,但是此时,只是当作子类自身的新的成员而已!
4 ,虽然父类的私有方法不能被重写,但是,如果子类重新定义了一个同名的方法的时候,方法参数 的形式(参数的个数)还是需 要和父类保持一致 !
class Student{
private $stu_age;
private $stu_name;
public function set_age($age){
if (is_int($age)&&$age>=0 &&$age<=150) {
$this->stu_age=$age;
} else {
echo "非法的年龄信息";
return false;
}
}
}
$stu=new Student;
$stu->set_age(10.5);//调用类中公开的接口
//echo $stu-> stu_age;//报错! Fatal error : Cannot access private property Student::$stu_age,改为public则可以访问
var_dump($stu);//非法的年龄信息…… //可以有效控制用户的行为--封装优点
//当set_age()10;时object(Student)#1 (2) { ["stu_age":"Student":private]=> int(10) ["stu_name":"Student":private]=> NULL },可以看到但类外不能访问
私有化属性,私有化方法
给 MySQLDB 类增加三个公开的方法:
fetchAll : 得到所有的记录(比较适合查询结果是多行多列的情况)
fetchRow : 得到一条记录(比较适合查询结果是单行的结果集)
fetchColumn : 得到一条记录的第一个字段(比较适合查询结果是单行单列的结果集)
final 类: 也叫作最终类,不能被继承,只能实例化对象
final 最终类其实就是实际开发过程中的一种语法上的规范 !
最终方法final method
当一个类还需要继承,但是不希望该类中的某些方法被重写,可以使用最终方法。
当该类被其他的类所继承的时候,该最终方法不能被重写!
六、abstract类: 抽象类,不能实例化对象,只能被继承
抽象类其实就是不完整的类,所以无法实例化一个真实的对象! 需要下一级的类去 实现 (完善方法体)!
而继承它的类也只有两种选择:1 要么完成父类(抽象类)中的抽象方法(完善方法体)2 要么继续做抽象类!
abstract class Animal{
public function move(){
}
}
class Bird extends Animal{
public function move(){
echo "I can fly! ";
}
}
class Snake extends Animal{
public function move(){
echo "I can creep! ";
}
}
$bird=new Bird;
$bird->move();//I can fly!
$snake=new Snake;
$snake->move();//I can creep!
特别强调
如果一个类继承自一个抽象类,而其自身不是一个抽象类,则必须实现父类中的所有的抽象方法!
抽象类中,不但可以包括抽象方法,还可以包括其他任意的普通成员(属性、常量、非抽象方法),都可以被子类所继承
抽象类的作用
可以完成普通类的继承,为其他的类提供公共的代码!
抽象类往往用于规定子类中必须要完成的方法或者成员,规定子类的方法结构,有时候为了保证完成一系列功能相似的多种操作类的结构一致,我们要求这些类都继承自一个相同的抽象类!
在 PHP 中定义一个接口 ,其实就是一种纯粹的规范或规定 ,规定该接口的下级类必须要 “实现” 的公共方法!
在一个接口中,只能 出现两种成员 :
接口常量, 抽象方法: 没有方法体的方法,但是此时, 抽象方法中所有 方法必须声明为 public (与抽象类中的抽象方法不同)
要使接口作用到类上,就必须使用 implements 关键字,意思为“实现”,其实和继承的本质是一样的!
当一个类“实现”一个接口的时候,也只有两种选择:
实现该接口中所有的公开的抽象方法(完善方法体)
如果该类没有实现接口中的部分(或全部)公开的抽象方法,就应该把该类声明成抽象类,然后等待更下一级的类去实现!此时,没有被实现的方法最好继续声明成抽象方法!
interface I_animal{
public function move();
public function eat();
}
interface I_shengwu{
public function sleep();
}
abstract class Human implements I_animal,I_shengwu {// 接口支持多实现。这也是接口和抽象方法的本质区别。
public function move(){}
public function eat(){}
abstract public function sleep();
}
接口与抽象类的比较
接口不是类(需要用interface来进行声明,需要其他类用implements实现 ),但抽象类是类(需要class进行声明,需要用extends继承 )
从逻辑或结构上看,接口可以看成是抽象类的一个“子集”,比抽象类更“抽象”,只有抽象方法和常量 没有其他的普通的方法
类只支持单继承,而接口支持多实现。这也是接口和抽象方法的本质区别。
4.接口与抽象类都可以作为其他类的规范,都可以规定下级类的内部结构,但是在真实的项目中,接口使用的要多一些!
interface I_USB{
const WIDTH=10;
const HEIGHT=4;
public function load();
public function run();
}
class MOuse implements I_USB{
public function load(){
echo "加载鼠标驱动 ";
}
public function run(){
echo "鼠标运行 ";
}
}
class Disk implements I_USB{
public function load(){
echo "加载移动硬盘驱动 ";
}
public function run(){
echo "移动硬盘运行 ";
}
}
$mouse=new MOuse;
$mouse->run();//鼠标运行
PHP-OOP4 ( 伪重载、 后期静态绑定 、单例模式、工厂模式、数据存储:系列与反系列)
一、PHP 中重载(伪重载)
为一个不存在的属性赋值的时候,PHP触发不同的方法,于是支持将该属性重新载入到当前的对象的内部,这种现象就叫作属性重载!
PHP 是可以采取相应的操作来处理对不可访问的成员的操作的控制!(以上是系统的默认行为)
PHP不支持重载,但是可以利用其它方式实现类似 重载的功能。
class Student{
public $stu_id;
public $stu_name;
}
$stu=new Student;
$stu->stu_id=9527;
$stu->stu_name='华安';
$stu->stu_age=25;//本来没有age值,php自动以类似重载方法插入该公共属性和值
var_dump($stu);
object(Student)#1 (3) { ["stu_id"]=> int(9527) ["stu_name"]=> string(6) "华安" ["stu_age"]=> int(25) }
所以,根据所处理的成员不同,重载又分成两种情况:
1、属性重载
根据对不可访问的属性的操作方式不同,系统分别由不同的魔术方法来处理:
一共有四个魔术方法:主要作用是让用户取得处理控制权
1为不可访问的属性赋值: __set()
该魔术方法需要两个参数 : 该不可访问的属性的属性名和 属性的值
一旦定义了__set()魔术方法,为不可访问的属性赋值的时候,就会自动的执行该方法,此时,处理权就交给用户自己了!
2获得不可访问的属性的值: __get()
一旦定义了 __get() 魔术方法, 获取不可访问的属性的值的时候, 就会自动的执行该方法,此时,处理权就交给用户自己了!
该魔术方法,只需要一个参数,就是该属性的属性名!
注意: __get 和 __set 两个方法往往在真实的项目中都是成对出现的!而且,往往就是利用这两个方法批量的对对象的私有属性进行处理!
3删除不可访问的属性: __unset()
但是,如果该属性是不可访问的(比如 private 或不存在),则会自动执行 __unset 方法,究竟是否可以删除成功,还是取决于 __unset 的内部实现!
4判断不可访问的属性是否存在: __isset()
如果该属性是不可访问的属性,判断这个属性是否存在的时候,会自动触发该方法的执行!
同样的,该方法也需要一个参数,技术当前需要判断的属性名 !
2、 方法重载: 指访问不可访问的方法的时候的处理方式!
方法重载是通过两位的两个魔术方法来完成的:
__call()
当调用一个不可访问的对象方法(非静态方法),会自动的执行该魔术方法!
参数一: 方法名, string 型, 参数二: array 型,因为参数的个数不确定,只能把所有的参数都放到一个数组里面
假如这个方法什么都不做:
当调用一个不可访问的类方法(静态方法)的时候,会自动执行该魔术方法,定义这个方法的时候,需要在方法名
的前面加上 static 关键字,因为该方法应该是一个静态方法!
class Student{
private $stu_id;
private $stu_name;
private $stu_age;
private $stu_money;
public function __set($name,$value){//增加__set方法
$allow_set=array('stu_id','stu_money','stu_name','stu_age');
if (in_array($name, $allow_set)) {
$this->$name=$value;
}
}
public function __get($name){//增加__get方法
$allow_get=array('stu_id','stu_name');
if (in_array($name, $allow_get)) {
return $this->$name;
}else{
return false;
}
}
public function __unset($name){//增加__unset方法
$allow_unset=array('stu_age','stu_money');
if (in_array($name, $allow_unset)) {
unset($this->$name);
}else{
return false;
}
}
public function __isset($name){//增加__isset方法
$allow_isset=array('stu_id','stu_money','stu_name','stu_age');
if (in_array($name, $allow_isset)) {
return true;
}else{
return false;
}
}
public function __call($name,$arr){//当调用一个不可访问的非静态方法时,自动执行
// var_dump($arr);
echo "对不起,您调用的非静态方法不存在 ";
}
public static function __callstatic($name,$arr){//当调用一个不可访问的静态方法时,自动执行
// var_dump($arr);
echo "对不起,您调用的静态方法不存在 ";
}
}
$stu=new Student;
$stu->stu_id=9527;
$stu->stu_name='华安';
$stu->stu_age=25;
$stu_teacher="大虎";
var_dump($stu);
// echo $stu->stu_age;
unset($stu->stu_age);
var_dump($stu);//stu_age属性和值被删除
var_dump(isset($stu->stu_name));//bool(true)
$stu->showName(10,20);//对不起,您调用的非静态方法不存在
Student::showName();//对不起,您调用的静态方法不存在
一个小案例(伪重载): 设计一个数学类
class Math{ //PHP不支持重载,但是可以利用其它方式实现类似重载的功能。
public function __call($name,$arr){
if ($name=='f1') {//判断用户调用的方法是否为f1
$length=count($arr);//根据参数的额个数进行业务逻辑处理
if ($length<1||$length>3) {
echo "非法的参数个数";
}elseif ($length==1) {
return $arr[0]*$arr[0];
}elseif ($length==2) {
return $arr[0]*$arr[0]+$arr[1]*$arr[1];
}elseif ($length==3) {
return $arr[0]*$arr[0]*$arr[0]+$arr[1]*$arr[1]*$arr[1]+$arr[2]*$arr[2]*$arr[2];
}
}
}
}
$obj=new Math;
echo $obj->f1(10); //100
echo " ";
echo $obj->f1(10,20); //500
echo " ";
echo $obj->f1(10,20,30);//36000
完善属性重载: 完善__set(),完善__get(),完善__unset(),完善__isset()
完善方法重载: MySQLDB 类的单例模式
第一步:增加一个私有的静态属性,用于保存对象
第二步:把构造方法私有化
第三步:增加一个获得单例的公共方法
第四步:私有化克隆魔术方法
三、后期静态绑定
1 、 $this 是不是永远代表其代码所在类直接实例化出来的对象? 不是, $this 是要根据上下文的执行环境来决定的!
2、 self 是不是永远代表其 代码所在 类的类名? 回答:是
总结一下 static 的功能,一共有三个了:
定义静态局部变量(和变量的生命周期相关)
定义静态成员(静态方法和静态属性)
代表“当前类”
总结,目前代表类的关键字一共有几个了? 一共有三个:
self : 当前类(在预编译阶段绑定),在哪就是哪的类。
static : 当前类(后期静态绑定),谁用就是谁的类。
什么是设计模式?
所谓的设计模式,并不是一种新的语法,而是人们在实际的应用中面对某种特定的情形而设计出来的某种常见的有效的解决方案,只是经验的总结!
四、单例模式
通过某些技巧从语法上使得一个类只能开辟一个对象空间的话,就可以节省相应的对象资源,这种模式就叫作单例模式!
四步走、实现单例模式的最典型的做法: 也叫作“三私一公”!
class MySQLDB{
//3增加一个私有属性,用于保存第一次实例出来的对象
private static $instance;
//1私有化构造方法,阻止无限地new实例出来
private function __construct(){
}
//2增加 静态 公开方法,去生产实例
public static function getInstance(){
if(!self::$instance instanceof self){
self::$instance=new self;
}
return self::$instance;
}
//4私有化__clone方法
private function __clone(){
}
}
// $obj=new MySQLDB;
// var_dump($obj);// Fatal error : Call to private MySQLDB::__construct() from invalid context in
$db1=MySQLDB::getInstance();
var_dump($db1);// object(MySQLDB)#1 (0) { }
$db2=MySQLDB::getInstance();
var_dump($db2);// object(MySQLDB)#1 (0) { }
// $db3=clone $db2;
// var_dump($db3);// Fatal error : Call to private MySQLDB::__clone() from context
五、工厂模式
工厂模式的含义就是:设计一个类(此时这个类可以叫作“工厂类”),该类的作用就是帮助其他的类“生产”对象,
也就是说,只要传递给这个“工厂”一个类名,就可以得到一个相应的对象!
//利用工厂模式生产对象
class A{
}
class B{
}
class Factory{
public static function getInstance($class_name){
return new $class_name;//可变对象
}
}
//利用工厂得到对象
$aaa=Factory::getInstance('A');
var_dump($aaa);//object(A)#1 (0) {}
$bbb=Factory::getInstance('B');
var_dump($bbb);//object(B)#2 (0) {}
利用工厂方法,生产单例对象
但是这里的单例,实现的方式并不是“三私一公” !
class DanFactory{
private static $instance=array();
public static function getInstance($class_name){
if (file_exists('./'.$class_name.'.class.php')) {
include_once './'.$class_name.'.class.php';
if (!isset(self::$instance[$class_name])|| !self::$instance[$class_name] instanceof $class_name) {
self::$instance[$class_name]=new $class_name;
}
return self::$instance[$class_name];
}else{
die("系统错误,没有找到相关的类!");
}
}
}
//利用工厂得到对象
$aaa=DanFactory::getInstance('A');
var_dump($aaa);//object(A)#1 (0) {}
$bbb=DanFactory::getInstance('B');
var_dump($bbb);//object(B)#2 (0) {}
$ccc=DanFactory::getInstance('A');
var_dump($ccc);//object(A)#1 (0) {}
六、1、数据的存储
也就是数据被持久化!一般的,可以将数据存放到数据库或者文件磁盘介质中!
当 PHP 脚本运行结束的时候,内存中的数据都会丢失,脚本的资源也都会消失(包括脚本中的数据),所以,如果想
实现数据存储,就应该在脚本运行结束之前进行数据的持久化!
在将数据自动转换成字符串的时候,同时在字符串内记录原数组的值和类型等相关的信息,目的就是在
得到数据的时候,能根据存储的信息(包含数据类型)转换成原始数据!
2、数据的序列化与反序列化
将原始数据转换成可以用于保存和传输的字符串数据!(不仅仅记录原数组的值,还记录原数据的类型等相关信息)
serialize(): 序列化--- 在数据存放到文件之前先进行序列化:
数据的反序列化: 将序列化后的字符串数据,转换成原始数据!
unserialize(): 反序列化--- 在读取数据之前进行反序列化:
注意:
数据的序列化与反序列化适用于除了资源类型之外的任何的数据类型!包括对象和字符串本身!
1在将对象存储到文件之前进行序列化操作, 在输出对象之前进行反序列化时对象数据有问题?
反序列化的时候,也需要先找到对象所属的类,如果找不到,则对象会被反序列化成一个名字叫作 __PHP_Incomplete_Class 的类!这是一个系统预定义的类!
解决方案: 只需要在反序列化的时候找到这个对象所属的类就行了: 手动载入!或 自动载入!
2序列化的时候,资源型的属性 $link 被转换成了整型数据 0 !
解决方法:在序列化的时候不存储资源型数据,在反序列化的时候再打开相应的资源!
__sleep()
是在序列化一个对象的时候自动调用! 该方法用于规定哪些属性应该被序列化,实现的方式为:
返回一个索引数组,数组内的元素为需要被序列化的属性名的集合!
__wakeup() 是在一个对象反序列化的时候自动调用的! 主要用来对对象进行相关的初始化操作!
//在MySQLDB类中增加魔术方法__sleep()和__wakeup()
public function __sleep(){
return array('host','port','user','pass','charset','dbname');
}
public function __wakeup(){//初始化数据库三部曲
$this->my_connect();//连接数据库
$this->my_charset();//选择默认字符集
$this->my_dbname();//选择默认的数据库
}
function __autoload($class_name){//系列化
if (file_exists('./'.$class_name.'.class.php')) {
include_once './'.$class_name.'.class.php';
}else{
die("系统错误,没有找到相关的类!");
}
}
$arr=array(
'pass'=>'123456',
'dbname'=>'whereit'
);
$data=MySQLDB::getInstance($arr);
var_dump($data);
$s_data=serialize($data);//写入文件之前先将数据进行序列化
echo file_put_contents('./38.txt',$s_data);//返回值是写入的字符串的长度
function __autoload($class_name){//在反序列化的时候找到这对象所属的类就行:手动载入!自动载入!
if (file_exists('./'.$class_name.'.class.php')) {
include_once './'.$class_name.'.class.php';
}else{
die("系统错误,没有找到相关的类!");
}
}
$data=file_get_contents('./38.txt');
$u_data=unserialize($data);//在读数据之前进行反序列化
var_dump($u_data);
PHP-OOP5 (类的魔术方法、魔术常量、对象遍历,类型约束,类和对象的相关函数 ,命名空间)
一、魔术方法: 名字由系统定义,而方法体由用户自己编写的方法!
最大特点是:不需要用户手动调用,而是当特定的情况发生时,系统自动调用相关的魔术方法!
注意: __autoload不算是魔术方法,但是其语法形式很类似于魔术方法!
类的魔术方法
__construct(), __destruct(), __clone(), __get(), __set(), __unset(), __isset(), __call(), __callstatic(), __sleep(), __wakeup()
__invoke()
当我们把对象当做一个函数(或方法)来调用的时候,会自动执行该魔术方法
之所以可以使用匿名函数 $func 闭包对象成功地调用函数,就是因为闭包对象里面有一个 __invoke 魔术方法
__toString()
当我们把一个对象当成是一个字符串来使用的时候,会自动的执行该模仿方法!
public function __toString(){ return serialize($this);}// 返回值可以是该对象序列化成字符串的结果!
二、类的魔术常量
__LINE__ 文件中的当前行号
__TRAIT__trait的名称,trait是PHP实现代码复用的一种方法,类似于接口。(5.4开始支持)
__CLASS__: 代表的是当前的类名!
注意与 self 的区别:例return new __CLASS__;是错误的,无法new
self 是指该类的本身(一种结构,不仅仅包括类名),而 __CLASS__ 只是一个类名(类名只是类的一部分!)
但是:$classname=__CLASS__; return new $classname; 是可以new的,这里是可变类名的一种语法。
__METHOD__: 代表当前的方法名!--- 在类里echo __METHOD__;//结果A::showCLassName
对象的遍历受属性的访问控制的限制!
对象毕竟是有“生命力”的,可以自定义遍历!
对象的自定义遍历,就是指使用 foreach 遍历某一个类的对象的时候,可以在 foreach 的各个阶段,调用相应的自定义的方法来完成!
对象的自定义遍历,需要用到接口化编程 ,实现了一个名叫 Iterator 的系统预定义接口,那么我们在使用 foreach 遍历该类的对象的时候,就可以在 foreach 的各个阶段,调用相应的 自定义的方法 来实现!
Iterator里面有五个抽象方法:1 current — 返回当前元素,2 key — 返回当前元素的键,3 next — 向前移动到下一个元素
4 rewind — 返回到迭代器的第一个元素,5 valid — 检查当前位置是否有效
header('Content-type:text/html;charset=utf-8'); //对象的自定义遍历
class Person implements Iterator{
private $position = 0;
public $a;
public $e = array(1,2,3,4,5);
// 返回到迭代器的第一个元素
public function rewind(){
$this->position = 0;
}
// 判断是否有效
public function valid(){
return isset($this->e[$this->position]);
}
// 返回值
public function current(){
return $this->e[$this->position];
}
// 返回键
public function key(){
return $this->position;
}
// 指针下移
public function next(){
$this->position++;
}
}
$obj = new Person;
foreach($obj as $k=>$v){
echo $k,'=>',$v,' ';
}//0=>1,1=>2...4=>5
四、类型约束
数组类型约束
就是强制的要求函数或者方法的形参是一个数组!---数组类型约束 (array 参数)
对象类型约束
就是强制要求函数的实参必须是某一个类的对象!---对象类型约束 (类名 参数)
五、类和对象的相关函数
class_exists()---例: var_dump(class_exists('A'));//bool(true) 检查类A是否已定义
interface_exists() ---例: var_dump(interface_exists('I_test'));//bool(true)
method_exists() --- 例:$obj=new A;var_dump(method_exists($obj,'f1'));//bool(true)
两个参数: 第一个参数是对象变量, 第二个参数是方法的名字
get_class(): 获得一个对象所属的类名!--- 参数 一个对象
get_parent_class() 获得对象或类的父类! --- 参数 一个对象
get_class_methods() 作用就是返回该类的方法! --- 参数是 一个类, 返回的是一个数组。
注意:在类外只能打印出公共方法,在类内可以打印出所有方法。
公开的静态方法和公开的非静态方法都可以被返回,但是无法返回受保护的和私有的方法名(在类外执行的时候)!
get_class_vars() 函数的参数也只有一个,也是类名, 能返回公开的属性!
is_object() 判断一个变量是否为一个对象!
六、命名空间概述
一种用来将内存逻辑划分的功能,用来区分同名的类,函数和常量
1、基本语法: namespace 空间名字 ;
其中,空间的名字尊重基本标识符的命名规则(以字母、数字和下划线构成,不能以数字开头)
1如果一个脚本的开始需要定义命名空间,则必须在脚本 的最开始处 定义!(例标签前不能有空格 )
2 一个脚本周期内,可以定义多个命名空间,并且不同的空间内可以定义相同名称的函数、常量和类!
2、空间成员
一个命名空间的内部可以有任意的 PHP 代码,但 命名空间本身只“管辖”三种 空间成员: 常量、函数和类 ,其他的都不属于空间成员! 例: 变量不属于空间成员!
注意: 命名空间内部除了空间成员(类、常量和函数)受限制之外,其他的代码都是该怎么执行就怎么执行,不存在任意的区别!
3、子空间
同计算机的目录可以存在子目录一样,内存中的空间可以存在子空间!
目录: A/B/C ,其中, C 就是 B 目录的子目录,而 B 又是 A 的子目录
空间: namespace A\B\C; 其中空间 C 就是空间 B 的子空间,而空间 B 又是空间 A 的子空间(注意使用反斜杠 \ ),
其表示的含义是创建了一个名字为 C 的子空间!并且 A 空间和 B 空间也一起创建了!
注意:子空间不能直接访问父空间的内容。因为它们只是逻辑上的划分。
4、空间成员的访问:注意使用\反斜杆
PHP 提供了三种访问空间成员的方法: 非限定名称方法、限定名称访问和完全限定名称访问!
1非限定名称访问
所谓的非限定名称访问,就是指在访问空间成员的时候,没有指定具体的空间的名字 ,我们前面的访问方式都是属于非限定名称访问!
2限定名称访问
语法形式: 子空间名 \ 空间成员名-----例:namespace A\B; C\getName();
3完全限定名称访问
就是直接从根空间(类比网站根目录)开始绝对路径访问, 优势就是,可以在任意的空间访问其他任意空间的成员!
语法形式: \ 空间 1\ 空间 2\ …… \ 空间成员,其中第一个 \ 代表的是根空间!---例; namespace A\B \C; \A\B\sayHi();
5、空间引入
当一个脚本包含了另一个脚本的时候,就出现空间引入! 也就是在一个脚本中引入了另外一个脚本的命名空间!
那么问题来了,如何访问空间 Second 里面的成员呢?
6空间类的引入 注意:include和空间类引入都不能少,否则找不到进不到对应空间。
所谓的空间类的引入就是指把其他空间的类引入到当前的空间,在当前自己的空间就可以使用这个类了!
方案一:通过完全限定名称访问
namespace Second;
$stu=new \First\Student;
var_dump($stu);
方案二:把 First 空间的类引入到自己的空间( Second 空间)
//如果被引入的类的名字和当前空间原有的类的名字相同,就会出现冲突,通过起个别名解决。
use \First\Student as PHPstudent;//将First下面的Student类引入到当前的空间
$stu=new PHPstudent;//起了别名后直接使用别名
var_dump($stu);
7、全局空间
如果不给脚本定义命名空间,那么脚本中所有的内容(类、常量和函数)就都属于全局空间!
直接使用根空间访问全局空间的成员即可: 语法为: \ 全局空间成员
PHP-OOP6(PDO,增改删查,预处理,事务处理,异常)
一、php data object (php数据对象)//本节内容主要看代码
1、pdo为php提供了访问数据库的一个轻量级的一致接口
因此pdo是php访问数据库的一个抽象层,不管使用哪种数据库,都可以用相同的方法来查询和获取数据。
优点: pdo可以防止sql注入,安全性更好
sql注入的案例: 万能账号:' or 1 = 1#
万能密码:'or 1='1
2、PDO功能开启: 去掉php.ini中 extension=php_pdo_mysql.dll 前的 ‘;’。
3、PDO三个类:
PDO 类: PDO 的核心,主要用于数据的连接、发送 SQL 语句等 …
PDOStatement 类:主要用于解析结果集,实现预处理、事务处理等特殊功能 ……
PDOException 类:主要用于捕获 PDO 异常
二、PDO类
//注意:如果使用了命名空间,则要引入PDO类
use PDO;
use PDOException;
①构造函数 :PDO 类中使用了构造方法(面向对象中我们学习过了实例化类的时候可以给类中的构造方法传值)
PDO::__construct() ( string $dsn[, string $username [, string $password ]] )
$dsn :数据源,字符串类型,格式: mysql:host=localhost;dbname=project
返回:pdo对象$pdo
② PDO销毁:PDO类没有提供自动销毁的方法,为了节省内存,我们一般会手动销毁PDO对象。
将pdo对象赋值为null, 使用unset() 函数进行销毁
三、增改删查
(1)增改删int PDO:: exec ( string $statement )
主要功能:实现对 SQL 语句的执行操作,返回的是受影响的行总数 。
参数说明: $statement :要执行的 SQL 语句(要求是 insert/update/delete )
(2) string PDO:: lastInsertId() 主要功能:返回最后 一条插入 数据的 id 。
(3)查询
第一步: 获取pdostatement对象,例:$pdo->执行后得到$stmt
PDOStatement PDO:: query ( string $statement )
主要功能:实现对 SQL 语句的查询操作(针对 select 语句),返回 PDOStatement 对象
参数说明: $statement :就代表要执行的 select 查询语句。
第二步: 获取结果集相关数据
1、int PDOStatement::rowCount ( void ):返回数据表中的总行数
2、int PDOStatement::columnCount ( void ) :返回数据表中字段的总列数
3、fetch 说明:PDOStatement::fetch — 从结果集中获取下一行
语法:mixed PDOStatement::fetch ( int $fetch_style )实现对数据的遍历输出,每次只能遍历一条记录,然后指针向下移动一位!
4、PDO::FETCH_BOUND
需要结合PDO::FETCH_BOUND(bindColumn)来实现
语法:bool PDOStatement::bindColumn ( mixed $column , mixed &$param )
参数: $column 结果集的列号(从1开始索引), $param 要绑定到的变量名
说明:PDOStatement::fetchAll — 返回一个包含结果集中所有行的数组
5、参 数:$fetch_style 控制下一行如何返回给调用者,可选的值为:
a、PDO::FETCH_ASSOC :把一条记录遍历到关联数组中
b、PDO::FETCH_NUM :把一条记录遍历到索引型数组中
c、PDO::FETCH_BOTH :把一条记录遍历到混合型数组中
d、PDO::FETCH_OBJ :把一条记录遍历到对象中
e、PDO::FETCH_BOUND (bindColumn) :把某个变量绑定到结果集中的某个列
try{//PDO中的遍历操作
$mq='mysql';
$user='root';
$pass=123456;
$dbname=' whereit ';
$dsn="$mq:host=127.0.0.1;dbname=$dbname";
$pdo=new PDO($dsn,$user,$pass);
//设置PDO属性实现捕获逻辑异常
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$time=time();
// $sql="update user set `int`=$time";//查询
// $sql="delete from user where uid=8";//删除
$sql="select * from user";
// $flag=$pdo->exec($sql);
$flag=$pdo->query($sql);//$flag即 返回的 PDOStatement 对象
echo $pdo->lastInsertId();
var_dump($flag);
$count=$flag->rowCount();//获取结果集中的总行数
echo $count," ",$flag->columnCount() ," ";
//一、PDO::FETCH_ASSOC遍历
// foreach ($flag as $key) {//遍历方法1
// var_dump($key);
// echo " ";
// }
// for ($i=0; $i <$count; $i++) {//遍历方法2
// $row=$flag->fetch(PDO::FETCH_ASSOC);
// var_dump($row);
// }
// while ($row=$flag->fetch(PDO::FETCH_ASSOC)) {//遍历方法3
// var_dump($row);
// }
//二、绑定遍历
$flag->bindColumn(2,$username);//这里的索引是id
$flag->bindColumn(3,$email);
$flag->bindColumn(4,$int);
for ($i=0; $i <$count; $i++) {//遍历方法2
$flag->fetch(PDO::FETCH_BOUND);
echo $username,'-',$email,'-',$int;
echo " ";
}
//三、fetchAll遍历方法2
// $data=$flag->fetchAll(PDO::FETCH_ASSOC);
// for ($i=0; $i <$count; $i++) {
// echo $data[$i]['username'],'-',$data[$i]['email'],'-',$data[$i]['int'];
// echo " ";
// }
// if (!$flag) {//PDO中的逻辑错误(手工抛出异常)
// throw new PDOException("SQL语句执行失败!", 10000);
// }
}catch(PDOException $e){
echo "错误编号".$e->getCode()." ";
echo "错误行".$e->getLine()." ";
echo "错误信息".$e->getMessage();
}
unset($pdo);
echo " ";
四、PDO预处理
预处理功能就是在sql语句结构与形式相同的情况下,只有参数不同所采用的一种数据处理机制,极大地减少了带宽的浪费。
$sql = "insert into tb_admin values (null, :username,:password,:time)";
或者 $sql = "insert into tb_admin values (null, ?, ?, ?)";
做预处理时,可以使用文本标识也可以使用问号,两者的功能都是一致的,唯一的不同就是语法的不同。
①如果使用文本标识,其在数据传递时,要求数组是一个关联型数组
②如果使用问号标识,其在数据传递时,要求数组是一个索引型数组,索引从0开始
第二步:定义预处理语句 $stmt = $pdo->prepare($sql);
第三步,绑定或设置参数并发送(分 不使用bindParam, 使用bindParam两种情况 )
注意: 如果使用bindParam绑定参数,bindParam( )的第二个参数不能为一个具体值,因为bindParam第二个参数为引用传值
//两个方法使用预处理 ( 不使用bindParam, 使用bindParam )
header("Content-type:text/html;charset=utf-8");//1、设置响应头信息
try{
//2、实例化pdo类
$mq='mysql';
$user='root';
$pass=123456;
$dbname=' whereit ';
$dsn="$mq:host=127.0.0.1;dbname=$dbname";
$time=time();
$pdo=new PDO($dsn,$user,$pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
//3、组装SQL语句
$sql="insert into user values(null,:username,:email,:time)";//一1、预处理使用文本标识
// $sql="insert into user values(null,?,?,?)";//一2、预处理使用问号标识
//4、定义预处理语句
$stmt=$pdo->prepare($sql);
// //5、使用execute传递参数
// $username='sunba';
// $data=array(
// ':username'=>$username, // 0=>$username,
// ':email'=>$email, // 1=>$email,
// ':time'=>$time // 2=>$time
// );
// $stmt->execute($data);
// 二、预处理使用bindParam实现参数绑定(推荐)
// 5绑定参数
$stmt->bindParam(':username',$username);
$stmt->bindParam(':email',$email);
$stmt->bindParam(':time',$time);
//6设置参数
$username='zhouwu';
$stmt->execute(); //7执行预处理语句
}catch(PDOException $e){
echo "错误编号".$e->getCode()." ";
echo "错误行".$e->getLine()." ";
echo "错误信息".$e->getMessage();
}
五、事务处理:要想实现事务处理,要求:数据库必须是 innoDB引擎
开启事务 $pdo->beginTransaction()
当提交或者回滚一个事物之后,事物结束。接下来的操作将不再事物操作范围之中。
var_dump($pdo->inTransaction());//判断是否在事务中bool(true)
提交事务: $pdo-> commit;
// 同时操作数据库a表和b表,其中一个操作失败则事务回滚
try{
$mq='mysql';
$user='root';
$pass='123456';
$dbname=' whereit ';
$dsn="$mq:host=127.0.0.1;dbname=$dbname";
$time=time();
$pdo=new PDO($dsn,$user,$pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$pdo->beginTransaction();//开启事务处理
$sql1="update student set salary=salary-1000 where id<5";
$sql2="update user set `int`=$time w格式提供here uid<5";
var_dump($pdo->inTransaction());//判断是否在事务中bool(true)
echo " ";
$effect1=$pdo->exec($sql1);
$effect2=$pdo->exec($sql2);
if (!($effect1&&$effect2)) {
echo "false";
$pdo->rollBack();//数据处理失败,回滚事务
} else {
echo "true";
$pdo->commit(); //数据处理成功,提交事务
}
}catch(PDOException $e){
echo "错误编号".$e->getCode()." ";
echo "错误行".$e->getLine()." ";
echo "错误信息".$e->getMessage();
}
六1、什么是异常
PHP 5 提供了一种新的面向对象的错误处理方法。
异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程。这种情况称为异常。
2、异常发生时的执行流程
①当前代码状态被保存
②代码执行被切换到预定义的异常处理器函数
③根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行脚本。
3、PDO中的异常捕获
基本语法:
try {
存在潜在错误的代码;
//设置PDO属性实现捕获逻辑异常,在执行SQL语句之前
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::EOOMODE_SILENT);
if(逻辑错误) {
//手动抛出异常
throw new PDOException(‘错误的文本信息’,’错误号’);
}
} catch(PDOException $e) {
echo ‘错误号:’.$e->getCode();
echo ‘错误行号:’.$e->getLine();
echo ‘错误的文本信息:’.$e->getMessage();
}
4、 设置异常等级
通过PDO::setAttribute设置异常级别
语法:bool PDO::setAttribute ( int $attribute , mixed $value )
参数: $attribute :要设置的属性, $value :要设置的属性值
PDO::ATTR_ERRMODE :PDO异常级别
① PDO::ERRMODE_SILENT :常规错误,默认(致命错误等)
② PDO::ERRMODE_WARNING :警告错误
③ PDO::ERRMODE_EXCEPTION :异常错误
例如:$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::EOOMODE_SILENT);
七、PDO常用属性
获取属性:$pdo->getAttribute()
设置属性:$pdo->setAttribute()
① PDO::ATTR_AUTOCOMMIT :自动提交,常用于事务处理(语句事务)
参数值: 1 :自动提交, 0 :关闭自动提交
② PDO::ATTR_CASE :结果集大小写, 参数值:
PDO::CASE_LOWER ( 2 ):把结果集(字段名称)全部转化为小写
PDO::CASE_UPPER ( 1 ):把结果集(字段名称)全部转化为大写
PDO::CASE_NATURAL ( 0 ):正常返回
③ PDO::ATTR_PERSISTENT :长连接
默认为false,表示关闭长连接,设置为true,则开启长连接
注意:必须在pdo对象实例化之前设置 $pdo->setAttribute(PDO::ATTR_PERSISTENT,true);
短连接:连接 -》 发送 SQL 语句 -》 执行 SQL 语句 -》 关闭
长连接:连接 -》 发送 SQL 语句 -》 执行 SQL 语句 -》 发送 SQL 语句 -》 执行 SQL 语句 …
Smarty 模板引擎
apache压力测试,在cmd中测试,ab -n 请求次数 -c 并发量 网址
一、模板引擎概述
1 、为什么需要模板引擎
①混合式编程( HTML+PHP )
while($row=mysql_fetch_assoc($res)){
?>
}
?>
混合式编程优点:执行效率高、运行速度快
混合式编程缺点:代码后期几乎没有任何维护性可言
②项目的开发流程
理想流程:
与客户沟通确认需求 à 编写需求分析 à 与客户沟通确认 à 设计师设计项目模板 à 切片并编程 HTML 代码 à 程序员编写动态代码并整合到 HTML 代码中 à 项目测试 à 正式上线。
现实流程:
与客户沟通确认需求 à 编写需求分析 à 与客户沟通确认 à 设计师设计项目模板 à 切片并编程 HTML 代码 à 程序员编写动态代码并整合到 HTML 代码中 à 项目测试 à 客户确认,不满意 à 设计师设计项目模板 à 程序员编写动态代码并整合到 HTML 代码中 à … à 正式上线。
2 、什么是模板引擎
模板引擎的核心就是:把 HTML 代码与 PHP 代码强制分离的一套模板机制!
3 、模板引擎应用项目汇总
① ThinkPHP 框架(引入了模板引擎技术)
② CI 、 YII 、 Laravel 框架
③ DEDECMS 内容管理系统
④ ECSHOP 商城系统 …
4 、模板引擎技术核心
模板引擎的原理:将模板( html )中的标签( {$title},{$content} )替换成具体对应值。
模板引擎原理代码如下:
demo02_muban.html //一、编写html代码
demo02_muban.php
header('Content-type:text/html;Charset=utf-8');//1设置响应头信息
$title='Smarty模板引擎';//2读取数据表,获取动态数据$title和$content
$content='Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!';
$str=file_get_contents('demo02_muban.html');//3使用file_get_contents获取模板的内容
$str=str_replace('$title',$title,$str);//4替换$title和$content这两个模板标记
$str=str_replace('$content',$content,$str);
echo $str;//5输出模板内容
运行结果:
Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!
二、封装自定义模板引擎
目的:通过自定义模板引擎( template 类),实现标签的替换来理解模板引擎的运行原理
1 、定义 Template.class.php 模板引擎类
首先我们先定义一个能替换模板( html )中标签( {$title} )值的类( Template )。
第一步:先定义一个数组:用来保存模板中的标签。因为标签可以有多个,所以使用数组。例如 {$title} 标签 {$content} 标签 ...
第二步:定义 assign 方法:用于分配变量到模板文件中。
第三步:定义 display 方法:实现对模板标签的替换,并显示输出模板内容
class Template {二、定义Template.class.php模板引擎类
private $data=array();//定义一个数组,用于保存模板中的标签
//定义一个assign方法,用于分配变量到模板文件
public function assign($name,$value){
$this->data[$name]=$value;//如$this->data['title']=$title;
}
public function display($spl){//定义display方法显示输出模板内容
$str=file_get_contents($spl);//使用该方法获取文件的内容
foreach ($this->data as $k => $v) {
//实现对模板标记的替换,$k='title',$title
$str=str_replace('{$'.$k.'}',$v,$str);
}
echo $str;//显示输出模板的内容
}
}
2 、测试模板引擎是否可用
demo03_ceshi.php 示例代码:
首先要引入我们之前定义的 template 类文件,然后实例化 template 类,调用类中的 assign 方法把变量分配到模板中,调用类中的 display 方法实现对模板标签的替换和显示输出。
//三、测试模板引擎是否可用
header('Content-type:text/html;Charset=utf-8');//1设置响应头
$title='Smarty模板引擎';//2读取数据表,获取动态数据$title和$content
$content='最好的模板引擎之一';
include_once('Template.class.php');//3引入模板引擎类
$smart=new Template();//4实例化模板引擎类
$smart->assign('title',$title);//5通过assign方法分配变量到模板文件
$smart->assign('content',$content);
$smart->display('Htest.html');//6通过display方法显示输出模板内容
运行结果:
Smarty缓存技术
Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!
三、 Smarty 模板引擎
1 、什么是 Smarty 模板引擎
smarty 是一个基于 PHP 开发的 PHP 模板引擎。它提供了逻辑( PHP )与外在内容( HTML )的分离。
2 、为什么要选择 Smarty 模板引擎
Smarty 特点: ①速度 ②编译型(编译文件) ③缓存技术 ④插件技术 ⑤语句自由
不适合使用 Smarty 的场景: ①小项目 ②实时更新的项目(股票的走势图 … )
3 、下载 Smarty 模板引擎
①下载地址: http://www.smarty.net ,下载后如下所示:smarty-3.1.30.zip
②解压 Smarty 模板引擎,如下所示: smarty-3.1.30/libs
4 、部署 Smarty 模板引擎
①复制 libs 目录到项目的目录中
②更改 libs 文件夹名称为 smarty
③创建一个 templates 文件夹作为 smarty 的模板目录,该目录下文件有bak,smarty,templates
html 文件都放到这个文件夹下,如下图
php 文件存放位置和 templates 文件平级,如下图
④创建 php 入口文件与 html 模板文件demo01.rumen.php
⑤编写 php 入口文件与 html 模板文件
demo01_rumen.php 示例代码:
//1、设置响应头信息
header("Content-type:text/html;Charset=utf-8");
//2、载入smarty入口文件
include_once("smarty/Smarty.class.php");
//3、实例化smarty类
$smarty=new Smarty;
//4、通过assign方法分配变量到模板文件
$tit='Smarty缓存技术';
$cont='Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!';
$smarty->assign('title',$tit);
$smarty->assign('content',$cont);
//5、通过display方法显示输出模板内容到网页
$smarty->display('demo01.html');
templates/demo01.html 示例代码:
Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!
四、 Smarty 相关细节与执行流程
1 、使用 Smarty 六步走
①设置响应头信息(防止出现乱码)
header(‘Content-type:text/html; charset=utf-8’);
②载入 Smarty 入口文件(载入 Smarty 类)
include ‘smarty/Smarty.class.php’);
③实例化 Smarty 类
④更改 Smarty 对象的默认属性(左右分隔符 … )
⑤分配变量到模板文件( assign 方法)
$smarty->assign(‘ 标记名称 ’,’ 替换后的值 ’);
⑥显示输出模板的内容
$smarty->display(‘ 模板文件的名称 ’);
2 、 Smarty 中的自动生成机制
当快速入门案例运行完毕后,在 smarty 项目目录中,会自动生成一个 templates_c 的文件夹,此文件夹就是 smarty 的编译目录( compile 缩写,编译)
打开编译目录,如下所示:bbccf67a82bf0354d593b419a36ee0df79d30fb7_0.file.demo01.html.php
使用编辑器打开编译文件,如下图所示:
tpl_vars['title']->value;?>
tpl_vars['content']->value;?>
3 、 Smarty 的执行流程
4 、验证 Smarty 的执行流程
①找到编译文件,如下图所示:
'file_dependency' =>
array (
'bbccf67a82bf0354d593b419a36ee0df79d30fb7' =>
array (
0 => 'E:\\CZwj\\wdc\\smart01\\templates\\demo01.html',
1 => 1487118526,
2 => 'file',
),
),
默认情况下,编译文件会自动记录模板文件的位置以及文件的最后修改时间!
②修改 html 模板文件 (随便加个空格)
③重新访问 php 入口文件,编译文件如下图所示:
'file_dependency' =>
array (
'bbccf67a82bf0354d593b419a36ee0df79d30fb7' =>
array (
0 => 'E:\\CZwj\\wdc\\smart01\\templates\\demo01.html',
1 => 1656761129,
2 => 'file',
),
),
5 、思考题
当我们在模板文件中,敲一个回车,然后删除回车,问模板文件是否发生改变呢?
答案:即使我们从观看的角度观察什么也没改变,但是当你敲一个回车的时候,模板文件已经添加一个回车操作。然后再删除回车,又有一个删除的操作。
6 、 Smarty 中的相关属性
目的:修改在模板中( html )左右分解符的使用方式,为了避免与其他插件同时使用时发生冲突。比如 jQuery,css 中也会使用到 {} 这个符号。
left_delimiter :左分界符,默认为左花括号 {
right_delimiter :右分界符,默认为右花括号 }
demo02_shuxing.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty类
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
$smarty->left_delimiter='<{';
$smarty->right_delimiter='}>';
//5、通过assign方法分配变量到模板文件
$title = '更改左右分界符';
$content = '在Smarty中可以通过$smarty->left_delimiter或$smarty->right_delimiter来更改对象的默认属性';
$smarty->assign('title',$title);
$smarty->assign('content',$content);
//6、通过display方法显示输出模板内容
$smarty->display('demo02.html');
templates/demo02.html 示例代码:
7 、 Smarty 中的相关方法
基本语法: $smarty->assign(‘ 标记名称 ’,’ 替换后的值 ’); 主要功能:分配变量到模板文件。
② display 方法
基本语法: $smarty->display(‘ 模板文件的名称 ’); 主要功能:显示输出模板内容。
//4、通过assign方法分配变量到模板文件
$tit='Smarty缓存技术';
$cont='Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!';
$smarty->assign('title',$tit);
$smarty->assign('content',$cont);
//5、通过display方法显示输出模板内容到网页
$smarty->display('demo01.html');
五、 Smarty 中的设计篇
1 、模板注释
基本语法: {* 模板注释内容 *}
示例代码:
demo03.html 示例代码:
demo03_zhushi.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty类
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配变量到模板文件
$smarty->assign('title','Smarty注释');
//6、通过display方法显示输出模板内容
$smarty->display('demo03.html');
运行结果:
由上图可知, Smarty 注释属于服务器端注释(给开发人员查看),其在模板解析时就会自动忽略,而不会显示在浏览器中。
2 、模板中的变量
php 代码端可以向模板中分配不同形式的变量:普通变量,数组变量,对象变量。
①普通变量
demo04_bianliang.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty类
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配普通变量到模板文件中
$smarty->assign('name','小强');
$smarty->assign('age',20);
$smarty->assign('address','北京市昌平区');
// 分配数组变量到模板文件
$data = array('linux','apache','mysql','php'); //lamp
$smarty->assign('data',$data);
//分配 对象变量 到模板文件
$std = new stdClass();
$std->name = '旺财';
$std->age = 23;
$std->address = '北京市海淀区';
$smarty->assign('std',$std);
//分配常量
define("ROOT", getcwd());
//6、通过display方法显示输出模板的内容
$smarty->display('demo04.html');
在模板 templates/demo04.html 中显示如下图所示:
{* 普通变量 *}
{$name}
{$age}
{$address}
{* 数组变量 *}
{$data[0]} - {$data[1]} - {$data[2]} - {$data[3]}
{* 对象变量 *}
{$std->name}
{$std->age}
{$std->address}
20
北京市昌平区
linux - apache - mysql - php
旺财
23
北京市海淀区
3 、变量调节器
基本语法:
{$ 变量名称 | 调节器 : 参数 1: 参数 2…}
主要功能:实现对模板中的变量进行格式化操作。
在 Smarty 模板文件中,一共有 21 种变量调节器,但是不需要完全掌握,重点掌握以下几种:
{$var|cat:var2} :对两个字符串进行连接操作
{$var|date_format:”%H%M%S”} :对时间戳进行格式化操作
{$var|default:”value”} :当变量为空或不存在时,使用默认值
{$var|escape} :转码操作
{$var|lower} :把变量转化为小写形式
{$var|upper} :把变量转化为大写形式
{$var|nl2br} :把 \n 换行符转化为 br 标签(文件载入时常用)
{$var|replace:”aa”:”bb”} :替换操作
{$var|string_format:”%d”} :实现字符串格式化, %s ,格式化为字符串, %d 格式化为整型
{$var|strip_tags} :去除 html 标签
{$var|truncate:30:”…”} :字符串截取( 如果截取中文,需要开启 php_mbstring.dll 扩展 )
示例代码:
{* 变量调节器 *}
字符串连接:{$str1|cat:$str2}
时间格式化:{$time|date_format:'%Y-%m-%d %H:%M:%S'}
默认值:{$var|default:'这家伙很懒,什么都没有留下...'}
转码:{$str3|escape}
大写:{$str3|upper}
nl2br:{$str4|nl2br}
替换:{$str5|replace:'world':'smarty'}
字符串格式化:{$str6|string_format:'%d'}
去除html标签:{$str3|strip_tags}
截取字符串:{$str5|truncate:8:'...'}
4 、系统变量
{$smarty.get. 变量名称 } :相当于 PHP 原生代码中的 $_GET
{$smarty.post. 变量名称 } :相当于 PHP 原生代码中的 $_POST
{$smarty.cookies . 变量名称 } :相当于 PHP 原生代码中的 $_COOKIE
{$smarty.session . 变量名称 } :相当于 PHP 原生代码中的 $_SESSION
{$smarty.now} :获取当前系统的时间的时间戳,类似 time() 函数
以上系统变量,可以在 Smarty 模板文件中直接使用,其系统变量都是以 {$smarty} 打头的!
php 实例代码:
session_start();
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配变量到模板文件
$_SESSION['adminuser'] = 'admin';
//6、通过display方法显示输出模板的内容
$smarty->display('demo06.html');
示例代码:
get请求参数:{$smarty.get.page}
session数据:{$smarty.session.adminuser}
获取当前时间的时间戳:{$smarty.now|date_format:'%Y-%m-%d %H:%M:%S'}
session数据:admin
获取当前时间的时间戳:2017-02-15 17:29:29
5 、 Smarty 中的内建函数
① foreach 内建函数
基本语法:
{foreach from=$ 数组变量 item= 内容 name=foreach 名称 key= 索引下标 }
{foreachelse} 当要遍历的数组元素为空时,系统会自动执行 foreachelse
主要功能:实现对数组元素的遍历!
使用 foreach 遍历一维数组:
demo07_foreach.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配变量到模板文件
$lamp = array('linux','apache','mysql','php');
$smarty->assign('lamp',$lamp);
$persons = array(
);
$smarty->assign('persons',$persons);
$smarty->assign('data',array());
//6、通过display方法显示输出模板内容
$smarty->display('demo07.html');
{* 遍历一维数组 *}
{foreach from=$lamp item='value' name='fr'}
{$smarty.foreach.fr.iteration}、{$value}
{/foreach}
当前共有{$smarty.foreach.fr.total}个元素
{* 遍历二维数组 *}
{foreach from=$persons item='row' key='k'}
{$k}:{$row['name']}-{$row['age']}-{$row['email']}
{/foreach}
{*foreach的另一种写法*}
{foreach $persons as $k=>$v}
{$k}:{$v.name} - {$v.age} - {$v.email}
{/foreach}
{* foreachelse的使用 *}
{foreach from=$data item='value'}
{$value}
{foreachelse}
暂未查询到任何数据...
{/foreach}
1、linux 2、apache 3、mysql 4、php 当前共有4个元素
附加属性 name 的使用:
$smarty.foreach.name.index :获取循环的索引下标
$smarty.foreach.name.iteration :获取当前是第几次循环
$smarty.foreach.name.first :如果第一次循环时,此值为 true
$smarty.foreach.name.last :如果最后一次循环时,此值为 true
$smarty.foreach.name.total :获取循环的总次数
② include 内建函数
基本语法: {include file=’ 要包含文件的名称 ’ assign=’var’ …}
主要功能:实现对文件的包含操作。
示例代码:
templates/demo08.html 示例代码:
{include file='header.html' title='哈哈哈'}
{include file='footer.html' copyright='http://www.wdc.com'}
templates/header.html 示例代码:
templates/footer.html 示例代码:
运行结果:
哈哈哈
内容
http://www.wdc.com
③ insert 内建函数:实现对函数的扩展
基本语法: {insert name=’func’ assign=’var’ …}
特别注意:如果采用 insert 扩展 Smarty 函数,其函数的命名必须使用 insert_ 函数名称 ,否则无法使用 insert 进行载入!
demo09_insert.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
function insert_func($args) {
echo $args['title'].date('Y-m-d H:i:s');
}
//5、通过assign方法分配变量到模板文件
//6、通过display方法显示输出模板内容
$smarty->display('demo09.html');
demo.html 示例代码:
{insert name='func' title='当前系统时间:'}
运行结果:当前系统时间:2020-12-13 19:05:05
④ if…elseif…else.../if 内建函数(分支条件)
基本语法:
示例代码:
{if $day == 1}
星期一
{elseif $day == 2}
星期二
{elseif $day == 3}
星期三
{elseif $day == 4}
星期四
{elseif $day == 5}
星期五
{else}
周末
{/if}
⑤ ldelim 与 rdelim 左右分界符
主要功能:输出左右花括号。
Smarty模板引擎是目前业界最著名的模板引擎之一,其基本语法:{ldelim}$变量名称{rdelim}
运行结果: Smarty模板引擎是目前业界最著名的模板引擎之一,其基本语法:{$变量名称}
⑥ literal 内建函数
#content{width:400px;height:200px;border:1px #ccc solid;}
主要功能:把其标签中的内容当做普通文本直接输出,适用于 css 与 js 标签!
在smarty中,与samrty的{}区别,正常输出css或js解析的内容。
⑦ section 内建函数
基本语法:
{section loop= 要遍历的数组 name= 名称 start= 开始 step= 步阶 max= 最大值 }
loop :确认数组中有多少个元素, section 就会执行多少次
name :每次循环时,系统会将索引下标放入 name 中,数字索引,从 0 开始
当要遍历的数组为空时,系统会自动执行 sectionelse
{* 使用section遍历一维数组 *}
{section loop=$lamp name='sec1'}
{$smarty.section.sec1.iteration}、{$lamp[sec1]}
{/section}
当前共有{$smarty.section.sec1.total}个元素
{* 使用section遍历二维数组 *}
{section loop=$persons name='sec2'}
{$persons[sec2]['name']}-{$persons[sec2]['age']}-{$persons[sec2]['email']}
{/section}
{* 附加属性的使用 *}
{section loop=$lamp name='sec3' start=0 step=1 max=2}
{$lamp[sec3]}
{/section}
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配变量到模板文件
$lamp = array('linux','apache','mysql','php');
$smarty->assign('lamp',$lamp);
$persons = array(
array('name'=>'刘备','age'=>46,'email'=>'liubei@ whereit .cn'),
array('name'=>'关羽','age'=>43,'email'=>'guanyu@ whereit .cn'),
array('name'=>'张飞','age'=>40,'email'=>'zhangfei@ whereit .cn')
);
$smarty->assign('persons',$persons);
$smarty->assign('data',array());
//6、通过display方法显示输出模板内容
$smarty->display('demo13.html');
section 中的内置变量:
{$smarty.section.name.index} :获取循环索引
{$smarty.section.name.index_prev} :获取上一次索引,如果索引为 0 ,此值为 -1
{$smarty.section.name.index_next} :获取下一次索引,如果索引为 0 ,此值为 1
{$smarty.section.name.iteration } :当前是第几次循环,默认从 1 开始
{$smarty.section.name.first|last} :第一次或最后一次循环时条件为真
{$smarty.section.name.total} :循环的总次数
示例代码:
问题: foreach 循环与 section 循环有何区别呢?
答:①两者都可以实现对数组元素的遍历
② foreach 既可以对索引型数组也可以对关联型数组进行遍历
③ section 只能实现对索引下标从 0 开始且连续的索引型数组进行遍历
④ foreach 内建函数与 php 中的 foreach 类似, section 与 php 中的 for 循环类似
补充: section 的一点优势, section 可以一次循环多个索引数组,但是多个数组内的元素个数必须相同。
6 、 Smarty 中的自定义函数
① debug 函数
基本语法: {debug}
主要功能:实现对模板中的变量进行调试功能, 示例代码:
② html_checkboxes 函数:生成复选项
基本语法:
{html_checkboxes values=$cust_ids checked=$customer_id output=$cust_names separator=" "}
values :要求参数是一个数组,每个选项的 value 值
checked :要求参数是一个数组,选中的复选框
output :要求参数是一个数组,每个选项的输出文本
③ html_options 函数:生成下拉选项,详见如下实例
基本语法:
{html_options values=$cust_ids selected=$customer_id output=$cust_names}
values :要求是一个数组,代表下拉选框的 value 值
selected :要求是一个数组,代表选中的选项
output :要求是一个数组,代表选框的文本信息
④ html_radios 函数:生成单选框
基本语法:
{html_radios values=$cust_ids checked=$customer_id output=$cust_names separator=" "}
values :要求参数是一个数组,每个选项的 value 值
checked :要求参数是固定值,代表选中的单选框
output :要求参数是一个数组,每个选项的输出文本
html_checkboxes 、 html_options 、 html_radios 示例代码:
{* 生成复选框 *}
{html_checkboxes name='hobby' values=$values checked=$checked output=$output separator=' '}
{* 生成下拉选框 *}
{html_options values=$values selected=$checked output=$output}
{* 生成下拉框的另一种写法*}
{html_options name='hobby' options=$output selected=$checked}
{* 生成单选框 *}
{html_radios name='hobby' values=$values checked=2 output=$output separator=' '}
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过assign方法分配变量到模板文件
$values = array(0,1,2);
$checked = array(1);
$output = array('吃饭','睡觉','打豆豆');
$smarty->assign('values',$values);
$smarty->assign('checked',$checked);
$smarty->assign('output',$output);
//6、通过display方法显示输出模板内容
$smarty->display('demo15.html');
html_checkboxes 、 html_options 、 html_radios 最终运行结果:
六、 Smarty 中的程序篇
1 、 Smarty 中的常量
SMARTY_DIR : Smarty 模板目录(学习 Smarty 设计思想)
Smarty 源代码:
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR); //路径分隔符Windows:/\ Linux:/
}
if (!defined('SMARTY_DIR')) {
define('SMARTY_DIR', dirname(__FILE__) . DS); //返回绝对路径
}
2 、 Smarty 中的变量
$left_delimiter :设置 Smarty 的左分隔符
$right_delimiter :设置 Smarty 的右分隔符
$caching :开启缓存,布尔类型, true 代表开启, false 代表关闭,默认为 false
$cache_lifetime :缓存的生命周期
示例代码:
$smarty->left_delimiter='<{';
$smarty->right_delimiter='>}';
3 、 Smarty 中的常用方法
append 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
//5、通过append方法分配变量到模板文件
$smarty->append('data','北京');
$smarty->append('data','上海');
$smarty->append('data','广州');
$smarty->append('data','深圳');
$str=$smarty->fetch('demo16.html');
echo $str;
html 实例代码:
{foreach from=$data item='value'}
{$value}
{/foreach}
运行结果:北京 上海 广州 深圳
fetch示例代码:特别注意:fetch方法与display方法基本一致,只不过fetch方法没有输出功能而已!
templateExists 示例代码:如果调用的模板不存在,就输出定义好的内容。
//6、通过display方法显示输出模板内容
if($smarty->templateExists('demo.html')) {
$smarty->display('demo.html');
} else {
echo '系统正在维护中,请稍后再试...';
}
运行结果: 系统正在维护中,请稍后再试...
七、 Smarty 中的缓存技术
1 、缓存技术介绍
在项目开发中,一共存在三种常用技术:①编译技术 < ②缓存技术 < ③静态化技术
2 、缓存技术应用场景
Smarty 缓存并不是任何应用场景都可以使用的一种技术,只有在项目上线后,其模板文件以及动态数据不需要经常改变时,才适合使用缓存技术。
3 、开启 Smarty 缓存
$smarty->setCacheDir($cache_dir) :设置缓存目录,默认为 cache 文件夹
$smarty->caching=true :是否开启缓存, true 代表开启(最重要)
$smarty->cache_lifetime=3600 :设置缓存的生命周期
demo17_cache.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
$smarty->caching = true; //开启缓存功能
$smarty->cache_lifetime = 3600; //设置缓存文件的生命周期为1小时
//5、通过assign方法分配变量到模板文件
$smarty->assign('title','Smarty缓存技术');
$smarty->assign('content','Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!');
//6、通过display方法显示输出模板内容
$smarty->display('demo17.html');
demo17.html 示例代码:
运行结果:
Smarty缓存技术
Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!
4 、缓存中的自动生成
在以上案例运行完毕后, smarty 项目目录如下所示:smart\cache
打开 cache 文件夹,如下所示:0a157d29e733e379e3ace6f048ba57e1d6c059aa_0.file.demo17.html.cache.php
打开缓存文件后,如下图所示:
Smarty缓存技术是Smarty中一种非常重要的技术,其速度要快于编译技术!
所以由上可知,为什么缓存文件要快于编译文件,主要原因在于缓存文件,其缓存的是最终要显示的数据!
5 、探究缓存文件从何而来呢?
思考:①缓存文件时从模板文件直接生成的? ②缓存文件时从编译文件直接生成的?
答:缓存文件是由编译文件直接生成的!
6 、 Smarty 的完整执行流程
7 、 Smarty 缓存的作用
①加快项目的访问速度
②减少服务器的压力
③减少对数据库服务器的读取
8 、使用 Smarty 缓存减少数据库服务器的读取
要用到的知识点: is_Cached 函数,判断缓存文件是否存在
基本语法: $smarty->isCached(“tpl.tpl”);
demo18_mysql.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
$smarty->caching = true; //开启缓存
$smarty->cache_lifetime = 3600; //设置缓存文件的生命周期
//7、判断缓存文件是否存在
if($smarty->isCached('demo18.html')) {
$smarty->display('demo18.html');
exit;
}
//5、通过assign方法分配变量到模板文件
echo 'connect mysql ...';
echo ' ';
mysql_connect('localhost','root','mysql');
mysql_query('use org7188');
mysql_query('set names utf8');
//组装SQL语句
$sql = "select * from 188_archives where id = 510";
//执行SQL语句
$res = mysql_query($sql);
//解析结果集
$row = mysql_fetch_assoc($res);
$smarty->assign('title',$row['title']);
$smarty->assign('description',$row['description']);
//6、通过display方法显示输出模板内容
$smarty->display('demo18.html');
9 、清除 Smarty 模板缓存
问题:为什么要清除缓存?
答:有些情况下,缓存可能会阻止我们实时获取数据表中的数据,这个时候就需要使用清除缓存。要用到的知识点:
$smarty->clearCache( “ tpl.tpl ” ); // 清除某个模板页面的缓存
$smarty->clearAllCache(); // 清除所有缓存
特别注意:以上两种方法,可以不需要 caching ,也可以实现清除!
demo19_clearCache.php
$smarty->clearCache('demo19.html'); //清除demo19.html模板的缓存
//$smarty->clearAllCache(); //清除所有模板文件的缓存
10 、 Smarty 中的局部缓存
①为什么需要局部缓存
如上图所示:在有些页面中,如文章或产品的详细页面,有些数据如浏览次数是不需要进行缓存的,但是如文章标题、作者、
发布时间以及内容又需要进行缓存,我们把这种技术就称之为 “ 局部缓存技术 ” 。
②要用到的知识点,基本语法:
$smarty->assign( “ var ” , “ value ” , true)
使用 assign 方法的第三个参数,让变量不缓存!
在模板文件中,使用 nocache 属性,让变量不缓存!
让某个区域内的变量都不缓存,可以使用 nocache 标签
示例代码:
$smarty->display('hits',201,true);//1在php文件中使用assign方法的第三个参数,让变量不缓存!
{nocache}//3某个区域内的变量都不缓存
浏览次数:{$hits}
{/nocache}
11 、 Smarty 中的单页面多缓存
应用场景:根据文章的 id 显示文章的详细内容(详细内容页是固定的,每次只有参数不同)
http://www. whereit.cn/show.php?id=501 id 为 501 的文章
http://www. whereit.cn/show.php?id=502 id 为 502 的文章
http://www. whereit.cn/show.php?id=503 id 为 503 的文章
要用到的知识点,基本语法:
$smarty->display( “ tpl ” , “缓存标识” )
demo21_danCache.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
$smarty->caching = true;
//5、通过assign方法分配变量到模板文件
mysql_connect('localhost','root','mysql');
mysql_query('use org7188');
mysql_query('set names utf8');
//组装SQL语句
$id = $_GET['id'];
$sql = "select * from 188_archives where id = $id";
//执行SQL语句
$res = mysql_query($sql);
//解析结果集
$row = mysql_fetch_assoc($res);
$smarty->assign('title',$row['title']);
$smarty->assign('description',$row['description']);
$smarty->assign('hits',202); //设置文章的次数
//6、通过display方法显示输出模板内容
$smarty->display('demo21.html',$id);//根据文章的id显示文章的详细内容
运行结果:通过传递的 ID 不同生成不同的缓存文件
12 、 Smarty 中的缓存集合
应用场景:根据产品的类别以及分页的页面显示产品的列表信息(列表页是固定的,每次只有参数不同且参数是多个)
http://www. whereit.cn/list.php?cateid=1&page=2 产品类别为 1 且分页页面为 2 的产品列表
http://www. whereit.cn/list.php?cateid=2&page=4 产品类别为 2 且分页页面为 4 的产品列表
http://www. whereit.cn/list.php?cateid=3&page=6 产品类别为 3 且分页页面为 6 的产品列表
要用到的知识点,基本语法:
$smarty->display( “ tpl ” , $id1. ” | ” .$id2)
demo22_jiheCache.php 示例代码:
//1、设置响应头信息
header('Content-type:text/html; charset=utf-8');
//2、载入Smarty入口文件
include 'smarty/Smarty.class.php';
//3、实例化Smarty对象
$smarty = new Smarty();
//4、更改Smarty对象的默认属性
$smarty->caching = true;
//5、通过assign方法分配变量到模板文件
//组装SQL语句
$cateid = $_GET['cateid'];
$page = $_GET['page'];
$sql = "select * from goods where cateid={$cateid} and page={$page}";
$smarty->assign('sql',$sql);
//6、通过display方法显示输出模板内容
$smarty->display('demo22.html',$cateid.'|',$page);
运行结果:通过传值的不同生成不同的缓存文件
八、课程总结
1 、课程总结
①模板引擎概述
什么是模板引擎,底层原理,封装了一个自定义的模板引擎
② Smarty 模板引擎
什么是 Smarty 、 Smarty 的特点与不适用 Smarty 的应用场景、部署 Smarty 六步走
设置响应头信息
载入 Smarty 入口文件
实例化 Smarty 类
更改 Smarty 对象的默认属性
通过 assign 方法分配变量到模板文件
通过 display 方法显示输出模板内容
③ Smarty 的自动生成与执行流程
编译技术
相关属性 left_delimiter 、 right_delimiter
相关方法 assign 、 display
④设计篇
模板注释、变量、变量调节器 {$var| 变量调节器 : 参数 …} 、系统变量 {$smarty}
内建函数
foreach 、 include 、 insert 、 if 分支、 ldelim/rdelim 、 literal 、 section
smarty 中的自定义函数
debug 、 html_checkboxes 、 html_options 、 html_radios
⑤程序篇
SMARTY_DIR 、 DS
left_delimiter 、 right_delimiter
assign 、 display 、 append 、 fetch 、 templateExists
⑥缓存技术
开启缓存以及设置缓存的生命周期
缓存文件是从编译文件直接生成的
加快项目的访问速度
减少服务器的压力
减少数据库服务器的读取 is_Cached
清除缓存 clearCache 、 clearAllCache
局部缓存 assign(‘var’,’value’,true) 、 {$var nocache=true} 、 {nocache}…{/nocache}
单页面多缓存 display(‘demo.html’,$id);
缓存集合 display(‘demo.html’,$cateid.’|’.$page…);