Contents
PHP基本语法与原理学习
1. 简介
PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML中,尤其适合 web 开发。
2. 基本语法
- 标记
- html中分离
- 注释
- 命名空间
3. 基本数据类型
3.1 类型基本
- 查看类型、获取类型、设置类型、类型判别的相关函数
- var_dump()、get_type()
- 强制类型转换
- settype()函数
- is_type()
3.2 四种标量类型
- Boolean
- true或者false,不区分大小写
- integer
- 有符号整数,解析器自动识别
- 各种进制的整数
- float
- 浮点数,等同于double或者real
- 浮点数的相互比较
- string
- 字符串的表达方式
- 单引号
- 双引号
- heredoc
- nowdoc
- 变量解析
- 简单规则:当 PHP 解析器遇到一个美元符号($)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。
- 复杂规则:{}辅助解析,复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。
- 字符串相关函数、运算符
- ‘.’字符串连接
- 相关的正则表达式函数
- URL字符串函数
- 加密解密函数
- 字符串的类型与编码
- PHP中字符串由字节组成的数组与标记缓冲区长度的整数组成
- 只支持256的字符,相当于是字节缓冲,字符串的编码方式跟随文件
- 由于没有官方的字符转换函数,各种字符处理函数的默认编码方式不统一
- 字符串的表达方式
3.3 三种复合类型
- array
- 实际存放的是键值对
- key
- key的类型是integer或者string
- key值会存在强制类型转换的情况
- 优先转换为整型
- NULL被转化为空字符
- 数组和对象无法作为key值
- key值的自动更新
- 未指定key的情况下,key值将会自动使用最大的int键名加1作为key
- value为任意类型
- 常用函数
- unset释放
- foreach遍历
- array_values重建索引
- object
- 初始化
- 转化为对象
- 其余详见类与对象
- callable
- 函数以string形式传递
- 已实例化的object方法被作为array传递,0=>object本体,1对应方法名
3.4 两种特殊类型
- resource
- 保存了到外部资源的引用
- 对应的资源有特定的函数建立、使用
- 转换:无意义
- 释放资源方式:引用计数
- NULL
- 被判定为NULL的情况:被赋值为NULL、还未被赋值、被unset
3.5 伪类型
可以用于参数类型提示,感觉类似一种类型别名:mixed、number、callback、array|object、void
4. 变量与常量
4.1 变量
- 传递方式
- 默认传值赋值
- 用引用符可以传引用
- register_globals
- 作用自动生成变量
- 为了安全,建议禁用,利用预定义访问
- 预定义变量
- 超全局变量
- $GLOBALS等,详见https://www.php.net/manual/zh/reserved.variables.php
- 静态变量
- 可变变量
- 两个$,获取了一个普通变量的值作为这个可变变量的变量名
4.2 常量
- 范围是全局的
- 定义
- define
- const
- 只能包含标量类型
- 类常量
- 魔术常量
__LINE__
等,详见https://www.php.net/manual/zh/language.constants.predefined.php
5. 运算符
- 错误控制运算符
- PHP 支持一个错误控制运算符:@。当将其放置在一个 PHP 表达式之前,该表达式可能产生的任何错误信息都被忽略掉。
- 执行运算符
- 反单引号:PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。使用反引号运算符的效果与函数shell_exec()相同。
- 数组运算符:联合、相等、不等、全等
6. 函数
- 作用域
- PHP 中的所有函数和类都具有全局作用域,可以定义在一个函数之内而在之外调用,反之亦然。
- 不支持重载
- 可变函数:PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。
- 匿名函数
- 作为回调函数
- 作为变量自动继承Closure内置类
7. 类与对象
- 大部分关键字与概念与其他语言相似
- 类的自动加载机制
- 注册自动加载器
- 接口
- 使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。
- 接口可以继承
- 接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。
- trait
- 优先级
- 从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
- 多层trait
- trait的冲突
- 用as关键字
- insteadof
- 抽象方法
- 静态成员
- 静态方法
- 匿名类
- 对象的遍历
- foreach
- 实现iterator接口
- 魔术方法:初始化、析构、sleep etc.
- 对象复制
- 当对象被复制后,PHP 5 会对对象的所有属性执行一个浅拷贝(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。
- clone关键字进行深度拷贝,如果定义了
__clone()
方法,则新创建的对象(复制生成的对象)中的__clone()
方法会被调用,可用于修改属性的值(如果有必要的话)。
- 后期静态绑定: static::与self::
- 序列化serialize():返回一个包含对象的字节流
8. 生成器
生成器可以yield多次,提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
9. PHP执行原理与流程
- SAPI概念
-
PHP的执行模式与代码执行过程:单进程、多进程、多线程
-
CGI\CLI调用方式–>fastcgi php-fpm
-
zend engin : 词法分析->token->语法分析->opcode->解析器执行
10. PHP内存管理、数据结构实现、对象模型
- 内存管理三件事:申请内存、销毁内存、使用内存
- zend engin内存管理模型
- heap层管理原理:
- free\large\rest 内存列表
- 垃圾回收机制:周期性的引用计数、分层垃圾识别
- PHP弱类型的底层原理:PHP7中改进的zval
- PHP7中array类型底层Hashtable原理:bucket数组双链表—>bucket数组加单链表
- PHP中类与对象特性的实现:类方法、类成员变量、类静态方法、类静态变量、延迟绑定原理、单继承与接口实现
11. 参考
Yii1.1框架学习
采用MVC模式的Web框架,结构如下
1. Yii1.1工作流
1. 用户发出了访问 URL http://www.example.com/index.php?r=post/show&id=1
的请求, Web 服务器通过执行入口脚本 index.php
处理此请求。
2. 入口脚本创建了一个 应用 实例并执行。
3. 应用从一个叫做 request
的 应用组件 中获得了用户请求的详细信息。
4. 应用在一个名叫 urlManager
的应用组件的帮助下,决定请求的 控制器 和 动作 。在这个例子中,控制器是 post
,它代表 PostController
类; 动作是 show
,其实际含义由控制器决定。
5. 应用创建了一个所请求控制器的实例以进一步处理用户请求。控制器决定了动作show
指向控制器类中的一个名为 actionShow
的方法。然后它创建并持行了与动作关联的过滤器(例如访问控制,基准测试)。 如果过滤器允许,动作将被执行。
6. 动作从数据库中读取一个 ID 为 1
的 Post
模型。
7. 动作通过 Post
模型渲染一个名为 show
的 视图。
8. 视图读取并显示 Post
模型的属性。
9. 视图执行一些 小物件。
10. 视图的渲染结果被插入一个 布局。
11. 动作完成视图渲染并将其呈现给用户。
2. Application
App是requset的处理上下文,分析请求并分派到特定的controller执行,Yii::app()可以访问全局单例,基础目录可以通过配置文件修改,基础目录应该不可被直接访问(.htaccess),应用的具体功能由组件components来完成,组件按需加载,preload函数会预加载需要预加载的组件,核心组件会主动加载
生命周期:以webapp为例
-
- 检测配置文件、基础路径
CApplication::preinit(),做预初始化,实际未定义,沿用CModule的,空操作- initsystemhandlers 初始化错误与异常处理
- 注册核心组件
- 加载配置文件
attachbehaviors:添加行为,这个是component的方法,behaviors是组件具有的行为,可以被回调,但是webapp和app中,behaviors都为空,所以这里无意义- 预加载组件 preload,log,config中进行设置
- CwebApplication::init(),get request组件
- run():
- raise onBeginRequest() 事件,调用相应回调函数
- 处理request
- 处理request流程:解析创建运行controller
- raiseOnEndrequest():这里代码设置了程序中止和函数中止的回调;最终调用onendrequest()
3. Controller
控制器响应用户的request并执行request action,引入所需的models、渲染对应的view,默认动作为index
,defaultAction可以进行设置
- route:
- 用户用路由的形式来指定特定的控制器、动作、Module
- route:moduleID/controllerID/actionID e.g:post/edit
- 路由的具体形式可以设置配置、修改.htaccess的重写规则、修改服务器设置来实现
- Controller的创建:webapp解析route后响应对应的request时创建,指定了控制器的ID,具体流程如下:
- 如果CWebApplication::catchAllRequest属性被指定(成为一个不为空的array),那么用户的请求将被忽略并基于该属性解析id创建控制器,这一功能用于将应用设置为维护状态并先是一个静态提示页
- 若controllerMap中包含有id,将被创建为对应的控制器,如果不存在则抛出404异常;加入Module后稍有不同,将会检测是否是某一模块的控制器类,如果是,模块实例将被首先创建
- Action:action可以定义为控制器的方法或者类;定义为类时,需要继承CAction,修改actions方法,并在配置文件中指定action与类文件的对应关系;动作参数可以自动绑定,不需要一个个
$_GET()
>1.17开始,动作类的run()方法也支持自动参数绑定 - Filter:过滤器
- 过滤器在动作执行前后执行,过滤器可以中止后续动作与过滤器的执行;过滤器可以被定义为方法或者对象
- 过滤器的执行顺序视其在过滤器列表中的顺序而定,利用
+\-
符号指定动作与过滤器的对应关系
4. Model
模型是CModel
或其子类的实例。模型用于保持数据以及与其相关的业务逻辑。
– 表单模型
– AR模型
– 详细在后续表单与数据库操作中,如何更好地定义模型,见最佳MVC实践
5. View
视图是一个包含了主要的用户交互元素的PHP脚本.为了实现逻辑和界面分离,大段的逻辑应该被放置于控制器或模型中,而不是视图中。视图脚本内部可以利用$this
访问控制器的属性;也可以在控制器中主动推送数据到视图中;
$this->render('edit', array(
'var1'=>$value1,
'var2'=>$value2,
));
- layout:布局,webapp和control中的layout可以自定义来改变render()的调用过程
- widet, system view:系统视图(错误、log)
6. Component
代码结构上来说组件是非常基础的类,很多类都是继承它而来,组件拥有属性、event与behavior。
– property : 1. 申明为public变量;2. 或者通过getXXX(),setXXX()灵活定义;tips:get/set定义的大小写不敏感
– event:一个事件可以绑定多个句柄。当事件触发时, 这些句柄将被按照它们绑定到事件时的顺序依次执行。如果句柄决定阻止后续句柄被执行,它可以设置$event->handled
为true
。
– behaviors:行为是一个对象,其方法可以被它绑定的部件通过收集功能的方式来实现,行为类必须实现 IBehavior接口。要使用一个行为,它必须首先通过调用此行为的 attach()方法绑定到一个组件。然后我们就可以通过组件调用此行为方法:
// $name 在组件中实现了对行为的唯一识别
$component->attachBehavior($name,$behavior);
// test() 是行为中的方法。
$component->test();
已绑定的行为可以像一个组件中的普通属性一样访问。
7. Module
模块包含MVC,与应用类似,但是不能单独部署,使用模块便于后续的复用。
8. 最佳MVC实践
- model: 根据前后端的不同需求解耦合,不适合使用GET和POST直接访问后端的请求信息;避免嵌入html
-
view: 主要包含html和少量php,避免直接访问db、避免get\post,灵活适应布局、物件进行重用
-
controller:
- may access
$_GET
,$_POST
and other PHP variables that represent user requests; - may create model instances and manage their life cycles.
- should avoid containing embedded SQL statements, which are better kept in models.
- should avoid containing any HTML or any other presentational markup. This is better kept in views.
- controller逻辑要精简,主要逻辑在model中
- may access
9. Yii1.1+数据库
DAO建立在PHP的PDO基础上,可以用单一的接口访问不同的DBMS,并且方便的切换,Active Record实现了ORM,一个类代表一个表,一个实例代表一行数据。
9.1 DAO数据访问对象
DAO由以下几个类构成:
– CDbConnection 代表一个数据库连接
– CDbCommand SQL statement
– CDbDataReader 读取数据库查询结构的前向流
– CDbTransaction 数据库事务类
对数据库的操作可以分为几种:
– 建立连接: 建立连接需要进行配置,配置数据库类型或者指定数据库驱动等相关信息,视连接的类型而定;
– 执行数据库语句:语句分为两种,返回结果的,和没有结果的
1. execute();
2. query();
除此以外,数据库语句的定义方式也分直接语句和prepared statement两种,后一种涉及参数绑定;
– 返回查询结果: CDbDataReader;可以按行读取、可以遍历结果、可以一次性全部读取—>变量绑定列是一种更为灵活的读取方式
– 事务操作:
$transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
//.... other SQL executions
$transaction->commit();
}
catch(Exception $e) // an exception is raised if a query fails
{
$transaction->rollback();
}
9.2 Query Builder
用面向对象的方式进行query(),每一种SQL关键字对应一个成员方法;createCommand()不传入SQL语句,即返回一个querybuilder对象,可以进行链式的函数调用进行查询
9.3 Active Record
对象映射技术,每个AR类对应一个数据表或者视图,列就是AR类中的属性,一个AR实例代表一行
AR定义与数据库连接:
- 连接,访问应用里的数据库连接
- AR类的定义,需要覆盖有关表属性的方法
AR类对数据库的操作:
1. 创建记录:new一个然后save
2. 访问与修改记录:find()方法访问记录;find以后save,修改记录
3. 删除记录: 可以查询后删除,也可以利用类的静态方法删除
4. 数据验证,自动调用rules函数
5. 对比记录 epuals方法
6. 处理事务,与之前DAO的类似,区别不大
9.4 Relational Active Record
AR只能进行单表操作,而关系型AR,用于关系表之间的查询,可以内部声明关系,例如:belongs to,has_many,has_one,many_many;
关系型AR的操作和选项比较多,比较复杂,具体见官方文档。