当前位置:首页 > 程序设计 >
《PHP+MySQL动态网站开发从入门到精通》电子书封面

PHP+MySQL动态网站开发从入门到精通

  • 发布时间:2019年04月12日 12:06:59
  • 作者:张工厂
  • 大小:36.2 MB
  • 类别:网站开发电子书
  • 格式:PDF
  • 版本:原书扫描版
  • 评分:9.2

    PHP+MySQL动态网站开发从入门到精通 PDF 原书扫描版

      给大家带来的一篇关于网站开发相关的电子书资源,介绍了关于PHP、MySQL、网站开发方面的内容,本书是由清华大学出版社出版,格式为PDF,资源大小36.2 MB,张工厂编写,目前豆瓣、亚马逊、当当、京东等电子书综合评分为:8.6分

      Tags:php MySQL 网站开发 

      内容介绍

      真正可以从零开始的入门书,新手不了解深度,目前自学,解决了很多困扰我的问题!

      最新的PHP7书籍终于出版了,讲解非常详细,非常适合初学者!

      PHP的入门教程 讲解挺全的

      编辑推荐

      PHP是一种跨平台的开源的服务器端嵌入式脚本语言,MySQL是*流行的关系型数据库管理系统,它们的配合使得Web开发者能够快速地写出动态生成页面的脚本,从而在全球获得越来越多网站开发人员的青睐。本书的开发小组具有丰富的网站开发经验,筛选出适合教学的开发案例,详细介绍了PHP MYSQL 动态网站开发的所有重要知识。本书通过结合不同难度的案例,比较全面地介绍PHP MYSQL 动态网站开发技术。本书内容对于初学者来说理解起来极其容易,可以快速入门,只需要几个小时就可以自己编写一些简单的脚本。希望这本书能帮助喜欢PHP的朋友,完整掌握PHP MYSQL 动态网站开发的技术要点,并具备动态网站开发能力。

      内容简介

      本书循序渐进地介绍了PHP 7 MySQL 5.7开发动态网站的主要知识和技能,提供了大量的PHP和MySQL开发实例供读者实践。每一章都清晰地讲述了代码作用及其编写思路,使读者能在*短时间内迅速掌握PHP的应用开发技能。 全书共21章,分别介绍了PHP 7的基本概念、PHP服务器环境配置、PHP的基本语法、PHP的语言结构、字符串和正则表达式、数组、时间和日期、面向对象、错误处理和异常处理、PHP与Web页面交互、文件与目录操作、图形图像处理、Cookie与会话管理、MySQL 5.7数据库基础、数据表的基本操作、数据的基本操作、数据库的备份与还原、PHP操作MySQL数据库等,*后通过两个综合案例,使读者进一步巩固所学的知识,提高综合实战能力。 本书适合PHP MySQL动态网站开发的初学者,以及广大网站开发人员,也可供高等院校和培训学校相关专业的师生教学参考。

      内容节选

      PHP 7+Apache服务器的环境搭建

      Apache支持大部分操作系统,搭配PHP程序的应用,就可以开发出功能强大的互动网站。本节主要讲述PHP 7+Apache服务器的搭建方法。

      Apache简介

      Apache是世界排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台特性和安全性被广泛使用,是最流行的Web服务器端软件之一。

      和一般的Web服务器相比,Apache的主要特点如下。

      跨平台应用:几乎可以在所有的计算机平台上运行。

      开发源代码:Apache服务程序由全世界众多开发者共同维护,并且任何人都可以自由使用,充分体现了开源软件的特性。

      支持HTTP/1.1协议:Apache是最先使用HTTP/1.1协议的Web服务器之一,它完全兼容HTTP/1.1协议并与HTTP/1.0协议向后兼容。Apache已为新协议所提供的全部内容做好了必要的准备。

      支持通用网关接口(CGI):Apache遵守CGI/1.1标准并且提供了扩充的特征,如定制环境变量和很难在其他Web服务器中找到的调试支持功能。

      支持常见的网页编程语言:可支持的网页编程语言包括Perl、PHP、Python和Java等,支持各种常用的Web编程语言,使Apache具有更广泛的应用领域。

      模块化设计:通过标准的模块实现专有的功能,提高了项目完成效率。

      运行非常稳定,同时具备效率高、成本低的特点,而且具有良好的安全性。

      作者简介

      张工厂,微谷科技有限公司技术总监,技术主攻方向为PHP软件开发和MySQL数据库,具有很强的实战经验。长期从事PHP、MySQL的外包服务,对市场使用有着较为长期的经验。熟悉流行的电子商务应用规则,熟悉技术应用方案与方向。对PHP、MySQL系统有较为广泛与深入的认识。

      目录

      • 第1章  初识PHP 1
      • 1.1 PHP的发展 1
      • 1.1.1 PHP的概念 1
      • 1.1.2 PHP的发展历程 1
      • 1.1.3 PHP语言的优势 2
      • 1.2 PHP的应用领域 3
      • 1.3 PHP 7的新特点 3
      • 1.4 PHP常用开发工具 5
      • 1.4.1 PHP代码开发工具 5
      • 1.4.2 网页设计工具 6
      • 1.4.3 文本编辑工具 6
      • 1.5  高手私房菜 8
      • 1.6  经典习题 8
      • 第2章  配置PHP 7服务器环境 9
      • 2.1 PHP服务器概述 9
      • 2.2  安装PHP 7前的准备工作 10
      • 2.2.1 软硬件环境 10
      • 2.2.2 获取PHP 7安装资源包 10
      • 2.3 PHP 7 Apache服务器的环境搭建 12
      • 2.3.1 Apache简介 12
      • 2.3.2 关闭原有的网站服务器 13
      • 2.3.3 安装Apache 13
      • 2.3.4 将PHP与Apache建立关联 14
      • 2.4 PHP环境的集成软件 16
      • 2.5  实战演练——我的第一个PHP程序 19
      • 2.6  高手私房菜 20
      • 2.7  经典习题 20
      • 第3章  PHP 7的基本语法 21
      • 3.1 PHP标识符 21
      • 3.1.1 短风格 21
      • 3.1.2 script风格 21
      • 3.1.3 ASP风格 22
      • 3.2  编码规范 22
      • 3.2.1 什么是编码规范 22
      • 3.2.2 PHP中的编码规范 22
      • 3.3  常  量 24
      • 3.3.1 声明和使用常量 24
      • 3.3.2 内置常量 25
      • 3.4  变  量 27
      • 3.4.1 PHP中的变量声明 27
      • 3.4.2 可变变量与变量的引用 28
      • 3.4.3 变量作用域(variable scope) 29
      • 3.4.4 变量的销毁 32
      • 3.5  数据的类型 33
      • 3.5.1 什么是类型 33
      • 3.5.2 整型(integer) 34
      • 3.5.3 浮点型(float或double) 34
      • 3.5.4 布尔型(boolean) 34
      • 3.5.5 字符串型(string) 34
      • 3.5.6 数组型(array) 35
      • 3.5.7 对象型(object) 37
      • 3.5.8 NULL型 38
      • 3.5.9 资源类型(resource) 38
      • 3.5.10 数据类型之间的相互转换 38
      • 3.6  标量类型的声明 39
      • 3.7  运算符 40
      • 3.7.1 算术运算符 40
      • 3.7.2 字符串运算符 41
      • 3.7.3 赋值运算符 42
      • 3.7.4 比较运算符 42
      • 3.7.5 逻辑运算符 43
      • 3.7.6 按位运算符 44
      • 3.7.7 否定控制运算符 45
      • 3.7.8 错误控制运算符 45
      • 3.7.9 三元运算符 46
      • 3.7.10 运算符的优先级和结合规则 46
      • 3.8  表达式 46
      • 3.9  实战演练——创建多维数组47
      • 3.10 高手私房菜 47
      • 3.11 经典习题 48
      • 第4章  PHP语言结构 49
      • 4.1  内置函数 49
      • 4.2  自定义函数 50
      • 4.2.1 自定义和调用函数 50
      • 4.2.2 向函数传递参数值 50
      • 4.2.3 向函数传递参数引用 51
      • 4.2.4 从函数中返回值 52
      • 4.2.5 对函数的引用 53
      • 4.2.6 对函数取消引用 54
      • 4.3  包含文件 54
      • 4.3.1 require和include 54
      • 4.3.2 include_once和require_once 55
      • 4.4  流程控制概述 55
      • 4.5  条件控制结构 56
      • 4.5.1 单一条件分支结构(if语句) 56
      • 4.5.2 双向条件分支结构(if…else语句) 57
      • 4.5.3 多向条件分支结构(elseif语句) 58
      • 4.5.4 多向条件分支结构(switch语句) 59
      • 4.6  循环控制结构 60
      • 4.6.1 while循环语句 60
      • 4.6.2 do…while循环语句 61
      • 4.6.3 for循环语句 62
      • 4.6.4 foreach循环语句 63
      • 4.6.5 流程控制的另一种书写格式 64
      • 4.6.6 使用break/continue语句跳出循环 66
      • 4.7  实战演练1——条件分支结构综合应用67
      • 4.8  实战演练2——循环控制结构综合应用69
      • 4.9  高手私房菜 70
      • 4.10 经典习题 70
      • 第5章  字符串和正则表达式 71
      • 5.1  字符串的单引号和双引号71
      • 5.2  字符串的连接符 72
      • 5.3  字符串的基本操作 74
      • 5.3.1 手动和自动转义字符串中的字符 74
      • 5.3.2 计算字符串的长度 74
      • 5.3.3 字符串单词统计 75
      • 5.3.4 清理字符串中的空格 75
      • 5.3.5 字符串的切分与组合 76
      • 5.3.6 字符串子串的截取 77
      • 5.3.7 字符串子串替换 78
      • 5.3.8 字符串查找 78
      • 5.3.9 大小写转换 79
      • 5.4  什么是正则表达式 80
      • 5.5  正则表达式语法规则 80
      • 5.6  实战演练——创建酒店系统在线订房表 85
      • 5.7  高手私房菜 88
      • 5.8  经典习题 89
      • 第6章  PHP数组 90
      • 6.1  什么是数组 90
      • 6.2  数组的类型 90
      • 6.2.1 数字索引数组 90
      • 6.2.2 关联索引数组 92
      • 6.3 PHP 常量数组 92
      • 6.4  数组构造 93
      • 6.4.1 一维数组 93
      • 6.4.2 多维数组 93
      • 6.5  遍历数组 95
      • 6.5.1 遍历一维数字索引数组 95
      • 6.5.2 遍历一维联合索引数组 96
      • 6.5.3 遍历多维数组 97
      • 6.6  数组排序 98
      • 6.6.1 一维数组排序 98
      • 6.6.2 多维数组排序 100
      • 6.7  字符串与数组的转换 101
      • 6.8  向数组中添加和删除元素102
      • 6.8.1 向数组中添加元素 102
      • 6.8.2 从数组中删除元素 103
      • 6.9  查询数组中指定元素 105
      • 6.10 统计数组元素个数 106
      • 6.11 删除数组中的重复元素 108
      • 6.12 调换数组中的键值和元素值 108
      • 6.13 实战演练——数组的序列化 109
      • 6.14 高手私房菜 110
      • 6.15 经典习题 110
      • 第7章  时间和日期 111
      • 7.1  系统时区设置 111
      • 7.1.1 时区划分 111
      • 7.1.2 时区设置 111
      • 7.2 PHP日期和时间函数 112
      • 7.2.1 关于UNIX时间戳 112
      • 7.2.2 获取当前时间戳 112
      • 7.2.3 获取当前日期和时间 113
      • 7.2.4 使用时间戳获取日期信息 113
      • 7.2.5 检验日期的有效性 116
      • 7.2.6 输出格式化时间戳的日期和时间 116
      • 7.2.7 显示本地化的日期和时间 118
      • 7.2.8 将日期和时间解析为UNIX时间戳 119
      • 7.2.9 日期和时间在PHP和MySQL数据格式之间的转换 119
      • 7.3  实战演练1——比较两个时间的大小120
      • 7.4  实战演练2——实现倒计时功能 120
      • 7.5  高手私房菜 121
      • 7.6  经典习题 121
      • 第8章  面向对象编程 122
      • 8.1  类和对象的介绍 122
      • 8.2 PHP中类的操作 123
      • 8.2.1 类的声明 123
      • 8.2.2 成员属性 124
      • 8.2.3 成员方法 124
      • 8.2.4 类的实例化 124
      • 8.2.5 访问类中的成员属性和方法 125
      • 8.3  构造方法和析构方法 127
      • 8.4  访问方法 129
      • 8.5  类的继承 130
      • 8.6  高级特性 131
      • 8.6.1 静态属性和方法 131
      • 8.6.2 final类和方法 132
      • 8.7  抽象类和接口 134
      • 8.7.1 抽象类 134
      • 8.7.2 接口 135
      • 8.8  面向对象的多态性 136
      • 8.8.1 通过继承实现多态 137
      • 8.8.2 通过接口实现多态 138
      • 8.9  高手私房菜 139
      • 8.10 经典习题 139
      • 第9章  错误处理和异常处理 140
      • 9.1  常见的错误和异常 140
      • 9.2  错误处理 143
      • 9.2.1 php.ini中的错误处理机制 143
      • 9.2.2 应用DIE语句调试 144
      • 9.2.3 自定义错误和错误触发器 145
      • 9.2.4 错误记录 148
      • 9.3  异常处理 149
      • 9.3.1 异常的基本处理方法 149
      • 9.3.2 自定义的异常处理器 151
      • 9.3.3 处理多个异常 152
      • 9.3.4 设置顶层异常处理器 153
      • 9.4  实战演练——处理异常或错误154
      • 9.5  高手私房菜 155
      • 9.6  经典习题 156
      • 第10章  PHP与Web页面的交互 157
      • 10.1 使用动态内容 157
      • 10.2 表单与PHP 158
      • 10.3 表单设计 158
      • 10.3.1 表单基本结构 159
      • 10.3.2 文本框 159
      • 10.3.3 选项框 160
      • 10.3.4 单选按钮 162
      • 10.3.5 下拉列表 163
      • 10.3.6 重置按钮 165
      • 10.3.7 提交按钮 165
      • 10.4 传递数据的两种方法 168
      • 10.4.1 用POST方式传递数据 168
      • 10.4.2 用GET方式传递数据 168
      • 10.5 PHP获取表单传递数据的方法 170
      • 10.6 PHP对URL传递的参数进行编码 170
      • 10.7 实战演练——PHP与Web表单的综合应用 171
      • 10.8 高手私房菜 173
      • 10.9 经典习题 173
      • 第11章  PHP文件与目录操作 174
      • 11.1 文件操作 174
      • 11.1.1 文件数据的写入 174
      • 11.1.2 文件数据的读取 178
      • 11.2 目录操作 179
      • 11.3 文件的上传 184
      • 11.4 实战演练——编写文本类型的访客计算器 187
      • 11.5 高手私房菜 188
      • 11.6 经典习题 188
      • 第12章  图形图像处理 189
      • 12.1 在PHP中加载GD库 189
      • 12.2 图形图像的典型应用案例 191
      • 12.2.1 创建一个简单的图像 191
      • 12.2.2 使用GD2函数在照片上添加文字 193
      • 12.2.3 使用TrueType字体处理中文生成的图片 194
      • 12.3 Jpgraph库的使用 196
      • 12.3.1 Jpgraph的安装 196
      • 12.3.2 Jpgraph的配置 197
      • 12.3.3 制作柱形与折线统计图 197
      • 12.3.4 制作圆形统计图 199
      • 12.4 实战演练——制作3D饼形统计图 201
      • 12.5 高手私房菜 203
      • 12.6 经典习题 203
      • 第13章  Cookie和会话管理 204
      • 13.1 Cookie基本操作 204
      • 13.1.1 什么是Cookie 204
      • 13.1.2 创建Cookie 205
      • 13.1.3 读取Cookie 205
      • 13.1.4 删除Cookie 206
      • 13.2 认识Session 208
      • 13.2.1 什么是Session 208
      • 13.2.2 Session的基本功能 208
      • 13.2.3 Cookie与Session 208
      • 13.2.4 在Cookie或URL中存储Session ID 209
      • 13.3 会话管理 209
      • 13.3.1 创建会话 209
      • 13.3.2 注册会话变量 210
      • 13.3.3 使用会话变量 210
      • 13.3.4 注销和销毁会话变量 211
      • 13.4 实战演练——会话管理的综合应用 212
      • 13.5 高手私房菜 213
      • 13.6 经典习题 214
      • 第14章  MySQL数据库基础 215
      • 14.1 什么是MySQL 215
      • 14.1.1 客户机-服务器软件 215
      • 14.1.2 MySQL版本 216
      • 14.1.3 MySQL的优势 216
      • 14.2 启动服务并登录MySQL数据库 217
      • 14.2.1 启动MySQL服务 217
      • 14.2.2 登录MySQL数据库 218
      • 14.2.3 配置Path变量 220
      • 14.3 MySQL常用图形管理工具 221
      • 14.4 高手私房菜 222
      • 14.5 经典习题 222
      • 第 15 章  数据库的基本操作 223
      • 15.1 创建数据库 223
      • 15.2 删除数据库 224
      • 15.3 实战演练——数据库的创建和删除 225
      • 15.4 高手私房菜 227
      • 15.5 经典习题 228
      • 第 16 章  数据表的基本操作 229
      • 16.1 创建数据表 229
      • 16.1.1 创建表的语法形式 229
      • 16.1.2 使用主键约束 230
      • 16.1.3 使用外键约束 232
      • 16.1.4 使用非空约束 233
      • 16.1.5 使用唯一性约束 233
      • 16.1.6 使用默认约束 234
      • 16.1.7 设置表的属性值自动增加 235
      • 16.2 查看数据表结构 236
      • 16.2.1 查看表基本结构语句DESCRIBE 236
      • 16.2.2 查看表详细结构语句SHOW CREATE TABLE 237
      • 16.3 修改数据表 238
      • 16.3.1 修改表名 238
      • 16.3.2 修改字段的数据类型 239
      • 16.3.3 修改字段名 240
      • 16.3.4 添加字段 241
      • 16.3.5 删除字段 243
      • 16.3.6 修改字段的排列位置 244
      • 16.3.7 更改表的存储引擎 245
      • 16.3.8 删除表的外键约束 246
      • 16.4 删除数据表 247
      • 16.4.1 删除没有被关联的表 248
      • 16.4.2 删除被其他表关联的主表 248
      • 16.5 实战演练——数据表的基本操作 250
      • 16.6 高手私房菜 258
      • 16.7 经典习题 258
      • 第17章  数据的基本操作 260
      • 17.1 插入数据 260
      • 17.1.1 为表的所有字段插入数据 260
      • 17.1.2 为表的指定字段插入数据 262
      • 17.1.3 同时插入多条记录 263
      • 17.2 更新数据 265
      • 17.3 删除数据 267
      • 17.4 查询数据 269
      • 17.4.1 查询所有字段 272
      • 17.4.2 查询指定字段 273
      • 17.4.3 查询指定记录 274
      • 17.4.4 带IN关键字的查询 276
      • 17.4.5 带BETWEEN AND的范围查询 278
      • 17.4.6 带LIKE的字符匹配查询 279
      • 17.4.7 查询空值 281
      • 17.4.8 带AND的多条件查询 281
      • 17.4.9 带OR的多条件查询 282
      • 17.4.10 查询结果不重复 284
      • 17.4.11 对查询结果排序 285
      • 17.5 实战演练——数据表综合应用案例 289
      • 17.6 高手私房菜 297
      • 17.7 经典习题 297
      •  
      • 第18章  数据库的备份与还原 299
      • 18.1 数据备份 299
      • 18.1.1 使用MySQLdump命令备份 299
      • 18.1.2 直接复制整个数据库目录 305
      • 18.1.3 使用MySQLhotcopy工具快速备份 306
      • 18.2 数据恢复 306
      • 18.2.1 使用MySQL命令恢复 306
      • 18.2.2 直接复制到数据库目录 307
      • 18.2.3 MySQLhotcopy快速恢复 308
      • 18.3 数据库迁移 308
      • 18.3.1 相同版本的MySQL数据库之间的迁移 308
      • 18.3.2 不同版本的MySQL数据库之间的迁移 309
      • 18.3.3 不同数据库之间的迁移 309
      • 18.4 表的导出和导入 309
      • 18.4.1 使用SELECTI…INTO OUTFILE导出文本文件 309
      • 18.4.2 使用MySQLdump命令导出文本文件 312
      • 18.4.3 使用MySQL命令导出文本文件 315
      • 18.4.4 使用LOAD DATA INFILE方式导入文本文件 318
      • 18.4.5 使用MySQLimport命令导入文本文件 320
      • 18.5 实战演练——数据的备份与恢复 322
      • 18.6 高手私房菜 325
      • 18.7 经典习题 326
      • 第19章  PHP操作MySQL数据库 327
      • 19.1 PHP访问MySQL数据库的一般步骤 327
      • 19.2 连接数据库前的准备工作 327
      • 19.3 访问数据库 328
      • 19.3.1 使用mysqli_connect()函数连接MySQL服务器 329
      • 19.3.2 使用mysqli_select_db()函数更改默认的数据库 330
      • 19.3.3 使用mysqli_close()函数关闭MySQL连接 331
      • 19.3.4 使用mysqli_query()函数执行SQL语句 331
      • 19.3.5 获取查询结果集中的记录数 332
      • 19.3.6 获取结果集的一条记录作为枚举数组 333
      • 19.3.7 获取结果集的记录作为关联数组 334
      • 19.3.8 获取结果集中的记录作为对象 334
      • 19.3.9 使用mysqli_fetch_array()函数获取结果集记录 335
      • 19.3.10 使用mysqli_free_result()函数释放资源 335
      • 19.4 实战演练1——PHP操作数据库 336
      • 19.5 实战演练2——使用insert语句动态添加用户信息 337
      • 19.6 实战演练3——使用select语句查询数据信息 339
      • 19.7 高手私房菜 341
      • 19.8 经典习题 341
      • 第20章  新闻发布系统数据库设计342
      • 20.1 系统概述 342
      • 20.2 系统功能 343
      • 20.3 数据库设计和实现 343
      • 20.3.1 设计表 343
      • 20.3.2 设计索引 348
      • 20.3.3 设计视图 348
      • 20.3.4 设计触发器 349
      • 第21章  PHP MySQL开发论坛实战 350
      • 21.1 网站的需求分析 350
      • 21.1.1 需求分析 350
      • 21.1.2 网站功能模块分析 350
      • 21.2 数据库分析 351
      • 21.2.1 分析数据库 351
      • 21.2.2 创建数据表 351
      • 21.3 论坛的代码实现 352
      • 21.3.1 数据库连接相关文件 352
      • 21.3.2 论坛主页面 359
      • 21.3.3 新用户注册页面 364
      • 21.3.4 论坛帖子的相关页面 367
      • 21.3.5 后台管理系统的相关页面 378

      读书笔记

      PHP调整数组顺序使奇数位于偶数前(代码/闭包扩展)

      php如何实现原址排序数组使奇数位于偶数前面(代码)

      输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

      1、遍历数组,判断元素奇数偶数,push进新数组,空间换时间

      2、插入排序的思想 空间上是原址排序

      2.1从前往后遍历,判断当前的是奇数

      2.2从当前的开始,从后往前遍历,如果是偶数就往后一位移动

      2.3当前奇数插入位置

      for i=1;i<arr.length;i++
          target=arr[i]
          if arr[i]%2==1
              j=i-1
              while j>=0&&arr[j]%2==0
                  arr[j+1]=arr[j]
                  j--
              arr[j+1]=target
      <?php
      $arr=array(1,2,3,4,5,6,7,8,9,10);
      function reOrderArray($arr){
              $length=count($arr);
              //从前往后遍历
              for($i=1;$i<$length;$i++){
                      //判断当前元素是奇数
                      $target=$arr[$i];
                      if($target%2==1){
                              //从后往前遍历,如果有偶数就往后移动一位
                              $j=$i-1;
                              while($j>=0 && $arr[$j]%2==0){
                                      $arr[$j+1]=$arr[$j];
                                      $j--;
                              }   
                              //把奇数插入位置
                              $arr[$j+1]=$target;
                      }   
              }   
              return $arr;
      }
       
      $arr2=reOrderArray($arr);
      var_dump($arr2);
      array(10) {
        [0]=>
        int(1)
        [1]=>
        int(3)
        [2]=>
        int(5)
        [3]=>
        int(7)
        [4]=>
        int(9)
        [5]=>
        int(2)
        [6]=>
        int(4)
        [7]=>
        int(6)
        [8]=>
        int(8)
        [9]=>
        int(10)
      }

      调整数组顺序使奇数位于偶数前(闭包扩展)

      这道题意思就是,给所有奇数放到偶数前面,我们可以设置两个指针,一个从前往后,直到他扫到偶数,一个从后往前,直到他扫到奇数,然后交换两个数的位置,然后往下扫,当begin>end的时候停止。代码实现很简单,如下:

      <?php
      //调整数组,使奇数位于偶数前面
      
      function reorder($arr){
              $length = count($arr);
              $begin = 0;
              $end = $length - 1;
              while($begin < $end){
                      //向后移动begin,直到它指到偶数
                      while(($begin < $end) && (($arr[$end] & 0x1) != 0)){
                              $begin++;
                      }
      
                      //向前移动end,指到它指到奇数
                      while(($begin < $end) && (($arr[$end] & 0x1) == 0)){
                              $end--;
                      }
      
                      if($begin < $end){
                              $temp = $arr[$begin];
                              $arr[$begin] = $arr[$end];
                              $arr[$end] = $temp;
                      }
              }
              return $arr;
      }
      
      $arr = [1,2,3,4,5,6,7,8];
      var_dump(reorder($arr));

      上面需要注意的时,判断一个数是奇数还是偶数的时候,我用的$num & 0x1 如果等于1,则为奇数,等于0,则为偶数,效率比%要高一些。

      到这里,如果单纯对于这道题,已经算是完事了。

      但是如果题目一改,将所有偶数放于奇数前,你可能又要重写一个函数了。

      这时,需求又改了,将所有能被3整除的放到前面………

      所有负数放到前面…….

      写完以上那么多函数,发现这些函数都类似啊,只有判断条件不一样。

      我们可不可以将整个函数,解耦成两部分,一个是判断数字应该在函数的前半部分还是后半部分,一个是交换数组位置。

      这时候我们就用到了闭包,代码如下

      <?php
      //调整数组,使奇数位于偶数前面
      
      function reorder($arr, $func){
              $length = count($arr);
              $begin = 0;
              $end = $length - 1;
              while($begin < $end){
                      //向后移动begin,直到它指到偶数
                      while(($begin < $end) && (!$func($arr[$begin]))){
                              $begin++;
                      }
      
                      //向前移动end,指到它指到奇数
                      while(($begin < $end) && ($func($arr[$end]))){
                              $end--;
                      }
      
                      if($begin < $end){
                              $temp = $arr[$begin];
                              $arr[$begin] = $arr[$end];
                              $arr[$end] = $temp;
                      }
              }
              return $arr;
      }
      
      $func = function($condition){
              $flag = ($condition & 0x1) == 0;
              return $flag;
      };
      
      $arr = [1,2,3,4,5,6,7,8];
      var_dump(reorder($arr, $func));

       

      《PHP、MySQL与JavaScript学习手册》学习笔记与总结

      php常用系统函数大全

      字符串函数

      strlen:获取字符串长度,字节长度

      substr_count 某字符串出现的次数

      substr:字符串截取,获取字符串(按照字节进行截取)

      mb_strlen
      mb_substr

      strchr:与substr相似,从指定位置截取一直到最后

      strrchr(获取文件后缀名):与strchr一样,只是从右边开始查找字符

      strtolower:所有的字符都小写(针对英文字母)

      strtoupper:所有的字符都大写

      strrev:字符串反转(只能反转英文:英文存储只有一个字节),按照字节进行反转

      strpos:从字符串中找对应字符出现的位置(数字下标),从最左边开始找

      strrpos:与strpos一样,只是从字符串的右边开始找

      trim:去掉函数两边的字符,默认是空格

      str_split 函数把字符串分割到数组中。

      chunk_split() 函数把字符串分割为一连串更小的部分

      str_repeat("Shanghai",5);把字符串 "Shanghai " 重复 5 次

      str_replace('\\', '/', dirname(DIR))); 替换

      ucfirst 首字母大写

      时间日期函数

      time:得到当前时间的时间戳(整型:从格林威治时间1970年1月1日0时0分0秒开始)秒数

      date:时间序列化函数,将指定的时间戳转换成规定时间日期的显示格式(随意的字符串:有专业的格式符规定),如果没有指定时间戳,系统默认使用当前时间的时间戳

      strtotime:时间日期格式的字符串转换成对应的时间戳(只要是正确的英语时间表达方式,都可以进行转换)

      microtime:微秒时间戳,根据不同的要求返回不同的结果 混合 microtime (布尔类型 ),可以返回一个浮点数的时间,也可以返回一个数组(时间戳和微秒数)

      数学相关函数

      abs:绝对值

      floor:向下取整 floor(3.2) 结果等于3

      ceil:向上取整

      round:四舍五入

      rand:取得一个指定范围内的随机整数

      mt_rand:取得一个指定范围内的随机整数(效率更高)

      min:PHP 会将非数值的 string 当成 0,但如果这个正是最小的数值则仍然会返回一个字符串。如果多个参数都求值为 0 且是最小值,min() 会返回按字母表顺序最小的字符串,如果其中没有字符串的话,则返回数值的 0;

      max:PHP 会将非数值的字符串当成 0,但如果这个正是最大的数值则仍然会返回一个字符串。如果多个参数都求值为 0 且是最大值,max() 会返回其中数值的 0,如果参数中没有数值的 0,则返回按字母表顺序最大的字符串。对于多个数组,max从左到右比较;如果同时出现数组和非数组参数总把数组作为最大值返回;

      数组相关函数

      count() // 非数组返回1

      key:获取当前数组当前指针所指向的元素的下标

      current:获取的当前指针指向元素的数值

      next:获取下一个元素的值,并且将指针下移

      prev:获取上一个元素的值,并且将指针上移

      end :将指针移到数组的最后一个元素,并返回最终指针位置的值

      reset:将指针移到数组的第一个元素,返回最终指针位置的值

      array_keys:获取一个数组的所有键名,返回一个索引数组

      array_values:获取一个数组的所有值,返回一个索引数组

      explode:爆炸,将一个字符串按照某个指定的规则(通常是特殊字符),将数组分成多个段,每一段都当做一个数组的元素,返回一个索引数组

      split 类似 explode explode('.', 'abc.txt')等于split('\.','abc.txt')

      implode:粘合,将一个数组内部的所有元素按照某个指定的规则(特殊字符),将所有的元素拼接成一个字符串

      join() 把数组元素组合为一个字符串

      array_merge:合并,指的是将两个数组中的元素进行累计。如果后面的数组与前面的数组有下标(键名:关联)相同的,那么后面的元素的值会覆盖前面的;如果是索引的相同下标,会自动的修改下标叠加到前面的数组里。

      array_reverse — 返回反转后的数组

      array_flip — 交换数组中的键和值

      数据结构模拟函数

      array_shift:从数组的前面弹出元素,得到元素的值

      array_pop:从数组的后面弹出元素,获得元素的值

      array_unshift:从数组的前面压入元素,得到当前数组元素的个数

      array_push:从数组的后面压入元素,得到当前数组元素的个数

      判断变量

      is_bool:判断是否是布尔类型

      is_float:判断浮点型

      is_integer:判断整型

      is_object:判断对象

      is_array:判断数组

      is_string:判断字符串

      is_resource:判断资源

      is_scalar:scalar是标量的,判断是基本数据类型:整型,浮点型,布尔型和字符串型

      is_null 检测变量是否为NULL 是返回TRUE 否则返回false。1.被赋值为NULL;2.变量没被赋值;3.被unset()

      is_numeric:判断数字或者纯数字组成的字符串

      gettype:获得数据类型

      settype:改变数据类型

      isset

      unset() 如果在函数中 unset() 一个全局变量,则只是局部变量被销毁,而在调用环境中的变量将保持调用 unset() 之前一样的值,如果在函数中 unset() 一个通过引用传递的变量,则只是局部变量被销毁,而在调用环境中的变量将保持调用 unset() 之前一样的值。

      empty//array(),"",0,"0",NULL,FALSE 都返回true

      文件操作函数

      opendir(路径):打开一个路径资源(将路径内部的所有数据读入到内存)

      readdir(路径资源):从文件夹资源中读取当前资源指针所指向的文件的名字,指针会向下移动一位

      closedir(资源):释放对应的文件资源

      scandir(路径):读取一个路径内部的所有文件名,返回一个数组,数组的每一个元素都是文件名。

      file_exists:判断一个文件是否存在(文件是广义:路径和文件)

      is_dir:判断一个指定路径是否存在(文件夹)

      is_file:判断一个指定路径是否是文件(文件)

      mkdir:创建一个路径,如果路径存在就会报错

      rmdir:移除文件夹

      file_get_contents:从一个指定的文件内读取数据内容。

      file_put_contents:将指定的字符串写入到对应的文件

      fopen:打开一个文件资源

      fgetc:c代表character,一次读取一个字符

      fgets:s代表string,代表可以读取多个字符,取决于指定的读取长度或者是否碰到换行(最多只能读取一行数据)

      两个函数都是对当前资源指针进行操作,读取之后都会将指针下移

      fread:获取指定长度的数据直到文件结束

      fwrite:向文件资源指针所在的位置写入数据,写东西不会将当前位置已有的东西往后移,而是会覆盖

      fseek:将指针指定到对应的位置

      fclose:使用对应的文件资源

      copy:复制

      unlink:删除文件

      rename:重命名文件

      filemtime:m代表modify,文件最后被修改的时间

      filesize:文件大小(字节)

      fileperms:文件权限(Linux下的八进制)

      排序

      rsort() 函数用于对数组单元从高到低进行排序。
      asort() 函数用于对数组单元从低到高进行排序并保持索引关系。
      arsort() 函数用于对数组单元从高到低进行排序并保持索引关系。
      ksort() 函数用于对数组单元按照键名从低到高进行排序。
      krsort() 函数用于对数组单元按照键名从高到低进行排序。

      报错

      error_reporting(E_ALL)

      ini_set('display_errors', 1)

      常量

      define() 定义常量
      defined() 检测常量是否定义

      序列化

      serialize

      unserialize

      json_encode 对变量进行 JSON 编码

      json_decode 对JSON 格式的字符串进行编码

      编码

      base64_encode 本函数将字符串以 MIME BASE64 编码。在 BASE64 编码后的字符串只包含英文字母大小写、阿拉伯数字、加号与反斜线,共 64 个基本字符,不包含其它特殊的字符,因而才取名 BASE64。

      base64_decode 解码

      MySQL常用命令

      # @Date    : 2017-11-15 13:18:34
      # @Author  : 师兵范 (shibingfan@163.com)
       
      #常用MySQL数据库命令
      +------------+----------------+
      | COMD       |   DESCRIPTION  | 
      +------------+----------------+
      |ALTER       |修改            |
      |BACKUP      |备份            | 
      |\C          |取消输入        | 
      |CREATE      |创建            | 
      |DELETE      |删除行          | 
      |DESCRIBE    |表结构          | 
      |DROP        |删除            | 
      |EXIT(CTRL-C)|退出            | 
      |GRANT       |修改权限        | 
      |HELP(\h,\?) |帮助            | 
      |INSERT      |插入            | 
      |LOCK        |锁住            | 
      |QUIT(\q)    |退出            | 
      |RENAME      |重命名          | 
      |SHOW        |项目说明        | 
      |SOURCE      |从文件名执行命令| 
      |STATUS(\s)  |显示当前状态    | 
      |TRUNCATE    |清空表          | 
      |UNLOCK      |解锁表          | 
      |UPDATE      |更新数据        | 
      |USE         |打开数据库      | 
      +------------+----------------+
      #显示已有数据库
      mysql> SHOW databaseS; 
      +--------------------+
      | Database           |
      +--------------------+
      | information_schema |
      | drupal7            |
      | mysql              |
      | northwind          |
      | performance_schema |
      | shibingfan         |
      | sys                |
      | testdb             |
      +--------------------+
      8 rows in set (0.06 sec)
      #创建数据库
      mysql> CREATE DATABASE publications;
      Query OK, 1 row affected (0.03 sec)
      #使用数据库
      mysql> USE publications;
      Database changed
      #数据库授权
      mysql> GRANT ALL ON publications.* TO 'shibingfan'@'localhost' IDENTIFIED BY 'shibingfan';
      Query OK, 0 rows affected, 1 warning (0.00 sec)
      #创建数据库表
      mysql> CREATE TABLE classics(
          -> author VARCHAR(128),
          -> title VARCHAR(128),
          -> type VARCHAR(16),
          -> YEAR char(4))ENGINE  MyISAM;
      Query OK, 0 rows affected (0.08 sec)
      #查询表结构
      mysql> DESCRIBE classics;
      +--------+--------------+------+-----+---------+-------+
      | Field  | Type         | Null | Key | Default | Extra |
      +--------+--------------+------+-----+---------+-------+
      | author | varchar(128) | YES  |     | NULL    |       |
      | title  | varchar(128) | YES  |     | NULL    |       |
      | type   | varchar(16)  | YES  |     | NULL    |       |
      | YEAR   | char(4)      | YES  |     | NULL    |       |
      +--------+--------------+------+-----+---------+-------+
      4 rows in set (0.02 sec)
      #数据类型
      CHAR(n)   VARCHAR(n)
      BINARY(n) VARBINARY(n)
      TEXT(n)   TINYTEXT(n)   MEDIUMTEXT(n)  LONGTEXT(n)
      TINYBLOB(n)  BLOB(n)
      TINYINT   SMALLINT      MEDIUMINT      INT/INTEGER    BIGINT
      FLOAT     DOUBLE/REAL
      DATETIME  DATE          TIMESTAMP      TIME           YEAR
      INT UNSIGNED,  NOT NULL,  AUTO_INCREMENT,  KEY
      #添加表列id
      mysql> ALTER TABLE classics ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT KEY;
      Query OK, 0 rows affected (0.06 sec)
      Records: 0  Duplicates: 0  Warnings: 0
      #删除表列
      mysql> ALTER TABLE classics DROP id;
      Query OK, 0 rows affected (0.08 sec)
      Records: 0  Duplicates: 0  Warnings: 0
      #向表中添加数据
      mysql> INSERT INTO classics(author,title,type,year)VALUES('Shibingfan', 'LEARN MYSQL', 'EDUCATION', '1887');
      Query OK, 1 row affected (0.00 sec)
      #重命名表
      mysql> ALTER TABLE classics RENAME mytable ;
      Query OK, 0 rows affected (0.02 sec)
      #改变列数据类型
      mysql> ALTER TABLE mytable MODIFY year SMALLINT;
      Query OK, 5 rows affected (0.08 sec)
      #添加新列
      mysql> ALTER TABLE mytable ADD pages SMALLINT UNSIGNED;
      Query OK, 5 rows affected (0.08 sec)
      #重命名列
      mysql> ALTER TABLE mytable CHANGE type category VARCHAR(16);
      Query OK, 0 rows affected (0.31 sec)
      #删除列
      mysql> ALTER TABLE mytable DROP pages;//DROP命令不可逆
      Query OK, 5 rows affected (0.33 sec)
      #删除表
      mysql> DROP TABLE mytable;
      Query OK, 0 rows affected (0.02 sec)
      #创建索引
      mysql> ALTER TABLE mytable ADD INDEX(author(20));
      mysql> CREATE INDEX author ON mytable(author(20));//也可在创建表时添加索引
      Query OK, 5 rows affected (0.08 sec)
      #创建全文索引
      mysql> ALTER TABLE mytable ENGINE = MyISAM;		//将表转换为MyISAM
      mysql> ALTER TABLE mytable ADD FULLTEXT(author,title);
      #数据库查询
      SELECT * FROM mytable;
      SELECT author,title FROM mytable;
      SELECT COUNT(*) FROM mytable;			//计数
      SELECT DISTINCT author FROM mytable; 	//去重
      DELETE FROM mytable WHERE title = 'LEARN MYSQL';
      SELECT * FROM mytable WHERE author='Shibingfan';
      SELECT * FROM mytable WHERE author LIKE "Shi%";		//like关键字,模糊匹配
      SELECT author FROM mytable LIMIT 3;					//LIMIT关键字,限定返回的行数
      SELECT author FROM mytable LIMIT 3,1;				//LIMIT关键字,限定从表的什么位置开始返回多少行
      SELECT * FROM mytable WHERE MATCH(author,title) AGAINST('Shi'); //自然语言在FULLTEXT索引列上搜索
      SELECT * FROM mytable WHERE MATCH(author,title) AGAINST('+Shi -bing' IN BOLLEAN MODE);//布尔模式下搜索
      UPDATE mytable SET author='Shibf' WHERE author='shibingfan'; 	//更新数据
      SELECT author,title FROM mytable ORDER BY author;				//排序
      SELECT category,COUNT(author) FROM mytable GROUP BY category;	//分组
      #连接表,新建customers表
      SELECT * FROM mytable,customers WHERE mytable.isbn=customers.isbn;
      SELECT * FROM customers NATURAL JOIN mytable;		//自然连接,将相同列名的表自动合并
      SELECT * FROM customers JOIN mytable ON mytable.isbn=customers.isbn;
      SELECT author,title FROM mytable AS au,ti;			//AS重命名
      SELECT * FROM mytable,customers WHERE mytable.isbn=customers.isbn AND author='shibingfan';
       
       
      #事物
      #事物存储引擎InnoDB
      mysql> CREATE TABLE accounts(number INT, balance FLOAT, PRIMARY KEY(number))ENGINE InnoDB;
      mysql> INSERT INTO accounts(number,balance) VALUES(12345,1025.50);
      mysql> INSERT INTO accounts(number,balance) VALUES(67890,140.00);
      mysql> SELECT * FROM accounts ;
      +--------+---------+
      | number | balance |
      +--------+---------+
      |  12345 |  1025.5 |
      |  67890 |     140 |
      +--------+---------+
      #事物处理BEGIN, COMMIT, ROOLBACK
      mysql> BEGIN;
      mysql> UPDATE accounts SET balance=balance+25.11 WHERE number=12345;
      mysql> COMMIT; 		//确认提交,数据库发生更改
      mysql> ROLLBACK;	//回滚操作,数据库恢复到BEGIN之前的状态
      #使用EXPLAIN,得到查询快照,进而对查询进行优化
      mysql> EXPLAIN SELECT * FROM accounts WHERE number='12345';
      +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
      | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
      +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
      |  1 | SIMPLE      | accounts | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
      +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
      #备份和恢复
      mysql> LOCK TABLES mytable READ,accounts READ;		//锁定表UNLOCK TABLES;
      mysql> mysqldump -u user -ppassword publications;
      mysql> mysqldump -u user -ppassword publications mytable > mytable.sql;
      mysql> mysqldump -u user -ppassword publications --all-database > all_db.sql;
      mysql> mysqldump -u user -ppassword < all_db.sql;
      mysql> mysqldump -u user -ppassword -D publications < mytable.sql;

       

      PHP7协程概念以及实现方法

      php7协程知识点

      多任务 (并行和并发)

      在讲协程之前,先谈谈多进程、多线程、并行和并发。

      对于单核处理器,多进程实现多任务的原理是让操作系统给一个任务每次分配一定的 CPU 时间片,然后中断、让下一个任务执行一定的时间片接着再中断并继续执行下一个,如此反复。

      由于切换执行任务的速度非常快,给外部用户的感受就是多个任务的执行是同时进行的。

      多进程的调度是由操作系统来实现的,进程自身不能控制自己何时被调度,也就是说: 进程的调度是由外层调度器抢占式实现的

      而协程要求当前正在运行的任务自动把控制权回传给调度器,这样就可以继续运行其他任务。这与抢占式的多任务正好相反, 抢占多任务的调度器可以强制中断正在运行的任务, 不管它自己有没有意愿。如果仅依靠程序自动交出控制的话,那么一些恶意程序将会很容易占用全部 CPU 时间而不与其他任务共享。

      协程的调度是由协程自身主动让出控制权到外层调度器实现的

      回到刚才生成器实现 xrange 函数的例子,整个执行过程的交替可以用下图来表示:

      协程可以理解为纯用户态的线程,通过协作而不是抢占来进行任务切换。

      相对于进程或者线程,协程所有的操作都可以在用户态而非操作系统内核态完成,创建和切换的消耗非常低。

      简单的说协程 就是提供一种方法来中断当前任务的执行,保存当前的局部变量,下次再过来又可以恢复当前局部变量继续执行。

      我们可以把大任务拆分成多个小任务轮流执行,如果有某个小任务在等待系统 IO,就跳过它,执行下一个小任务,这样往复调度,实现了 IO 操作和 CPU 计算的并行执行,总体上就提升了任务的执行效率,这也便是协程的意义

      多线程

      在单核下,多线程必定是并发的;

      不过现在的统一进程的多线程是可以运行在多核CPU下,所以可以是并行的

      并发(Concurrency)

      是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。

      并行(Parallesim)

      是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
      多个操作可以在重叠的时间段内进行。

      并行和并发区别

      并发指的是程序的结构,并行指的是程序运行时的状态

      并行一定是并发的,并行是并发设计的一种

      单线程永远无法达到并行状态

      协程

      协程的支持是在生成器的基础上, 增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数).

      这就把生成器到调用者的单向通信转变为两者之间的双向通信.

      我们在上篇文章已经讲过了send方法, 下面让我们理解下协程

      同步代码

      在没有涉及到异步执行代码之前,我们的代码都是这样的

      function printNum($max, $caller)
      {
        for ($i=0; $i<$max; $i++ ) {
          echo "调度者:" . $caller . " 打印:" . $i . PHP_EOL;
        }
      }
       
      printNum(3, "caller1");
      printNum(3, "caller2");
       
      # output
      调度者:caller1 打印:0
      调度者:caller1 打印:1
      调度者:caller1 打印:2
      调度者:caller2 打印:0
      调度者:caller2 打印:1
      调度者:caller2 打印:2

      使用协程后改进的代码

      初稿,手动调整生成器执行

      # 本代码手动调整了进程执行代码的顺序,当然本代码实现不用协程也可以,只是利用本流程说明协程作用
      # 生成器给了我们函数中断,协程[生成器send]给了我们重新唤起生成器函数的能力
      function printNumWithGen($max)
      {
        for ($i=0; $i<$max; $i++ ) {
          $res = yield $i;
          echo $res;
        }
      }
       
      $gen1 = printNumWithGen(3);
      $gen2 = printNumWithGen(3);
       
      // 手动执行caller1 再 caller2
      $gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);
      $gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);
       
      // 手动执行caller1 再 caller2
      $gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);
      $gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);
       
      // 手动执行caller2 再 caller1
      $gen2->send("调度者: caller2 打印:" . $gen2->current() . PHP_EOL);
      $gen1->send("调度者: caller1 打印:" . $gen1->current() . PHP_EOL);
       
      # output
      调度者: caller1 打印:0
      调度者: caller2 打印:0
      调度者: caller1 打印:1
      调度者: caller2 打印:1
      调度者: caller2 打印:2
      调度者: caller1 打印:2

      总结

      上面案例应该让大家理解了协程设计的意义和如何使用协程

      那么接下去我们为我们的协程自动一个自动调度器(Co自动执行器),无需再手动来中断和恢复了

      PHP7下协程的实现方法

      前言

      相信大家都听说过『协程』这个概念吧。

      但是有些同学对这个概念似懂非懂,不知道怎么实现,怎么用,用在哪,甚至有些人认为yield就是协程!

      我始终相信,如果你无法准确地表达出一个知识点的话,我可以认为你就是不懂。

      我写这篇文章的目的,是想对鸟哥文章做更加充足的补充,毕竟有部分同学的基础还是不够好,看得也是云头雾里的。

      什么是协程

      先搞清楚,什么是协程。

      你可能已经听过『进程』和『线程』这两个概念。

      进程就是二进制可执行文件在计算机内存里的一个运行实例,就好比你的.exe文件是个类,进程就是new出来的那个实例。

      进程是计算机系统进行资源分配和调度的基本单位(调度单位这里别纠结线程进程的),每个CPU下同一时刻只能处理一个进程。

      所谓的并行,只不过是看起来并行,CPU事实上在用很快的速度切换不同的进程。

      进程的切换需要进行系统调用,CPU要保存当前进程的各个信息,同时还会使CPUCache被废掉。

      所以进程切换不到费不得已就不做。

      那么怎么实现『进程切换不到费不得已就不做』呢?

      首先进程被切换的条件是:进程执行完毕、分配给进程的CPU时间片结束,系统发生中断需要处理,或者进程等待必要的资源(进程阻塞)等。你想下,前面几种情况自然没有什么话可说,但是如果是在阻塞等待,是不是就浪费了。

      其实阻塞的话我们的程序还有其他可执行的地方可以执行,不一定要傻傻的等!

      所以就有了线程。

      线程简单理解就是一个『微进程』,专门跑一个函数(逻辑流)。

      所以我们就可以在编写程序的过程中将可以同时运行的函数用线程来体现了。

      线程有两种类型,一种是由内核来管理和调度。

      我们说,只要涉及需要内核参与管理调度的,代价都是很大的。这种线程其实也就解决了当一个进程中,某个正在执行的线程遇到阻塞,我们可以调度另外一个可运行的线程来跑,但是还是在同一个进程里,所以没有了进程切换。

      还有另外一种线程,他的调度是由程序员自己写程序来管理的,对内核来说不可见。这种线程叫做『用户空间线程』。

      协程可以理解就是一种用户空间线程。

      协程,有几个特点:

      • 协同,因为是由程序员自己写的调度策略,其通过协作而不是抢占来进行切换
      • 在用户态完成创建,切换和销毁
      • ⚠️ 从编程角度上看,协程的思想本质上就是控制流的主动让出(yield)和恢复(resume)机制
      • 迭代器经常用来实现协程

      说到这里,你应该明白协程的基本概念了吧?

      PHP实现协程

      一步一步来,从解释概念说起!

      可迭代对象

      PHP5提供了一种定义对象的方法使其可以通过单元列表来遍历,例如用foreach语句。

      你如果要实现一个可迭代对象,你就要实现Iterator接口:

      <?php
      class MyIterator implements Iterator
      {
       private $var = array();
       public function __construct($array)
       {
        if (is_array($array)) {
         $this->var = $array;
        }
       }
       public function rewind() {
        echo "rewinding\n";
        reset($this->var);
       }
       public function current() {
        $var = current($this->var);
        echo "current: $var\n";
        return $var;
       }
       public function key() {
        $var = key($this->var);
        echo "key: $var\n";
        return $var;
       }
       public function next() {
        $var = next($this->var);
        echo "next: $var\n";
        return $var;
       }
       public function valid() {
        $var = $this->current() !== false;
        echo "valid: {$var}\n";
        return $var;
       }
      }
      $values = array(1,2,3);
      $it = new MyIterator($values);
      foreach ($it as $a => $b) {
       print "$a: $b\n";
      }

      生成器

      可以说之前为了拥有一个能够被foreach遍历的对象,你不得不去实现一堆的方法,yield关键字就是为了简化这个过程。

      生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现Iterator接口的方式,性能开销和复杂性大大降低。

      <?php
      function xrange($start, $end, $step = 1) {
       for ($i = $start; $i <= $end; $i += $step) {
        yield $i;
       }
      }
      foreach (xrange(1, 1000000) as $num) {
       echo $num, "\n";
      }

      记住,一个函数中如果用了yield,他就是一个生成器,直接调用他是没有用的,不能等同于一个函数那样去执行!

      所以,yield就是yield,下次谁再说yield是协程,我肯定把你xxxx。

      PHP协程

      前面介绍协程的时候说了,协程需要程序员自己去编写调度机制,下面我们来看这个机制怎么写。

      0)生成器正确使用

      既然生成器不能像函数一样直接调用,那么怎么才能调用呢?

      方法如下:

      • foreach他
      • send($value)
      • current / next...

      1)Task实现

      Task就是一个任务的抽象,刚刚我们说了协程就是用户空间协程,线程可以理解就是跑一个函数。

      所以Task的构造函数中就是接收一个闭包函数,我们命名为coroutine。

      /**
       * Task任务类
       */
      class Task
      {
       protected $taskId;
       protected $coroutine;
       protected $beforeFirstYield = true;
       protected $sendValue;
      
       /**
        * Task constructor.
        * @param $taskId
        * @param Generator $coroutine
        */
       public function __construct($taskId, Generator $coroutine)
       {
        $this->taskId = $taskId;
        $this->coroutine = $coroutine;
       }
       /**
        * 获取当前的Task的ID
        * 
        * @return mixed
        */
       public function getTaskId()
       {
        return $this->taskId;
       }
       /**
        * 判断Task执行完毕了没有
        * 
        * @return bool
        */
       public function isFinished()
       {
        return !$this->coroutine->valid();
       }
       /**
        * 设置下次要传给协程的值,比如 $id = (yield $xxxx),这个值就给了$id了
        * 
        * @param $value
        */
       public function setSendValue($value)
       {
        $this->sendValue = $value;
       }
       /**
        * 运行任务
        * 
        * @return mixed
        */
       public function run()
       {
        // 这里要注意,生成器的开始会reset,所以第一个值要用current获取
        if ($this->beforeFirstYield) {
         $this->beforeFirstYield = false;
         return $this->coroutine->current();
        } else {
         // 我们说过了,用send去调用一个生成器
         $retval = $this->coroutine->send($this->sendValue);
         $this->sendValue = null;
         return $retval;
        }
       }
      }

      2)Scheduler实现

      接下来就是Scheduler这个重点核心部分,他扮演着调度员的角色。

      /**
       * Class Scheduler
       */
      Class Scheduler
      {
       /**
        * @var SplQueue
        */
       protected $taskQueue;
       /**
        * @var int
        */
       protected $tid = 0;
      
       /**
        * Scheduler constructor.
        */
       public function __construct()
       {
        /* 原理就是维护了一个队列,
         * 前面说过,从编程角度上看,协程的思想本质上就是控制流的主动让出(yield)和恢复(resume)机制
         * */
        $this->taskQueue = new SplQueue();
       }
       /**
        * 增加一个任务
        *
        * @param Generator $task
        * @return int
        */
       public function addTask(Generator $task)
       {
        $tid = $this->tid;
        $task = new Task($tid, $task);
        $this->taskQueue->enqueue($task);
        $this->tid++;
        return $tid;
       }
       /**
        * 把任务进入队列
        *
        * @param Task $task
        */
       public function schedule(Task $task)
       {
        $this->taskQueue->enqueue($task);
       }
       /**
        * 运行调度器
        */
       public function run()
       {
        while (!$this->taskQueue->isEmpty()) {
         // 任务出队
         $task = $this->taskQueue->dequeue();
         $res = $task->run(); // 运行任务直到 yield
      
         if (!$task->isFinished()) {
          $this->schedule($task); // 任务如果还没完全执行完毕,入队等下次执行
         }
        }
       }
      }

      这样我们基本就实现了一个协程调度器。

      你可以使用下面的代码来测试:

      <?php
      function task1() {
       for ($i = 1; $i <= 10; ++$i) {
        echo "This is task 1 iteration $i.\n";
        yield; // 主动让出CPU的执行权
       }
      }
      function task2() {
       for ($i = 1; $i <= 5; ++$i) {
        echo "This is task 2 iteration $i.\n";
        yield; // 主动让出CPU的执行权
       }
      }
      $scheduler = new Scheduler; // 实例化一个调度器
      $scheduler->newTask(task1()); // 添加不同的闭包函数作为任务
      $scheduler->newTask(task2());
      $scheduler->run();

      关键说下在哪里能用得到PHP协程。

      function task1() {
        /* 这里有一个远程任务,需要耗时10s,可能是一个远程机器抓取分析远程网址的任务,我们只要提交最后去远程机器拿结果就行了 */
        remote_task_commit();
        // 这时候请求发出后,我们不要在这里等,主动让出CPU的执行权给task2运行,他不依赖这个结果
        yield;
        yield (remote_task_receive());
        ...
      } 
      function task2() {
       for ($i = 1; $i <= 5; ++$i) {
        echo "This is task 2 iteration $i.\n";
        yield; // 主动让出CPU的执行权
       }
      }

      这样就提高了程序的执行效率。

      关于『系统调用』的实现,鸟哥已经讲得很明白,我这里不再说明。

      3)协程堆栈

      鸟哥文中还有一个协程堆栈的例子。

      我们上面说过了,如果在函数中使用了yield,就不能当做函数使用。

      所以你在一个协程函数中嵌套另外一个协程函数:

      <?php
      function echoTimes($msg, $max) {
       for ($i = 1; $i <= $max; ++$i) {
        echo "$msg iteration $i\n";
        yield;
       }
      }
      function task() {
       echoTimes('foo', 10); // print foo ten times
       echo "---\n";
       echoTimes('bar', 5); // print bar five times
       yield; // force it to be a coroutine
      }
      $scheduler = new Scheduler;
      $scheduler->newTask(task());
      $scheduler->run();

      这里的echoTimes是执行不了的!所以就需要协程堆栈。

      不过没关系,我们改一改我们刚刚的代码。

      把Task中的初始化方法改下,因为我们在运行一个Task的时候,我们要分析出他包含了哪些子协程,然后将子协程用一个堆栈保存。(C语言学的好的同学自然能理解这里,不理解的同学我建议去了解下进程的内存模型是怎么处理函数调用)

       /**
        * Task constructor.
        * @param $taskId
        * @param Generator $coroutine
        */
       public function __construct($taskId, Generator $coroutine)
       {
        $this->taskId = $taskId;
        // $this->coroutine = $coroutine;
        // 换成这个,实际Task->run的就是stackedCoroutine这个函数,不是$coroutine保存的闭包函数了
        $this->coroutine = stackedCoroutine($coroutine); 
       }

      当Task->run()的时候,一个循环来分析:

      /**
       * @param Generator $gen
       */
      function stackedCoroutine(Generator $gen)
      {
       $stack = new SplStack;
       // 不断遍历这个传进来的生成器
       for (; ;) {
        // $gen可以理解为指向当前运行的协程闭包函数(生成器)
        $value = $gen->current(); // 获取中断点,也就是yield出来的值
        if ($value instanceof Generator) {
         // 如果是也是一个生成器,这就是子协程了,把当前运行的协程入栈保存
         $stack->push($gen);
         $gen = $value; // 把子协程函数给gen,继续执行,注意接下来就是执行子协程的流程了
         continue;
        }
        // 我们对子协程返回的结果做了封装,下面讲
        $isReturnValue = $value instanceof CoroutineReturnValue; // 子协程返回`$value`需要主协程帮忙处理 
        if (!$gen->valid() || $isReturnValue) {
         if ($stack->isEmpty()) {
          return;
         }
         // 如果是gen已经执行完毕,或者遇到子协程需要返回值给主协程去处理
         $gen = $stack->pop(); //出栈,得到之前入栈保存的主协程
         $gen->send($isReturnValue ? $value->getValue() : NULL); // 调用主协程处理子协程的输出值
         continue;
        }
        $gen->send(yield $gen->key() => $value); // 继续执行子协程
       }
      }

      然后我们增加echoTime的结束标示:

      class CoroutineReturnValue {
       protected $value;
       
       public function __construct($value) {
        $this->value = $value;
       }
       // 获取能把子协程的输出值给主协程,作为主协程的send参数
       public function getValue() {
        return $this->value;
       }
      }
      function retval($value) {
       return new CoroutineReturnValue($value);
      }

      然后修改echoTimes:

      function echoTimes($msg, $max) {
       for ($i = 1; $i <= $max; ++$i) {
        echo "$msg iteration $i\n";
        yield;
       }
       yield retval(""); // 增加这个作为结束标示
      }

      Task变为:

      function task1()
      {
       yield echoTimes('bar', 5);
      }

      这样就实现了一个协程堆栈,现在你可以举一反三了。

      4)PHP7中yield from关键字

      PHP7中增加了yield from,所以我们不需要自己实现携程堆栈,真实太好了。

      把Task的构造函数改回去:

       public function __construct($taskId, Generator $coroutine)
       {
        $this->taskId = $taskId;
        $this->coroutine = $coroutine;
        // $this->coroutine = stackedCoroutine($coroutine); //不需要自己实现了,改回之前的
       }

      echoTimes函数:

      function echoTimes($msg, $max) {
       for ($i = 1; $i <= $max; ++$i) {
        echo "$msg iteration $i\n";
        yield;
       }
      }

      task1生成器:

      function task1()
      {
       yield from echoTimes('bar', 5);
      }

      这样,轻松调用子协程。

      总结

      这下应该明白怎么实现PHP协程了吧?

      实例分析PHP7的异常

      PHP 7 异常用于向下兼容及增强旧的assert()函数。它能在生产环境中实现零成本的断言,并且提供抛出自定义异常及错误的能力。

      老版本的API出于兼容目的将继续被维护,assert()现在是一个语言结构,它允许第一个参数是一个表达式,而不仅仅是一个待计算的 string或一个待测试的boolean。

      assert() 配置

      配置项默认值可选值
      zend.assertions1 1 - 生成和执行代码 (开发模式) 0 - 生成代码,但在执行时跳过它 -1 - 不生成代码 (生产环境)
      assert.exception0 1 - 断言失败时抛出,可以抛出异常对象,如果没有提供异常,则抛出 AssertionError 对象实例。 0 - 使用或生成 Throwable, 仅仅是基于对象生成的警告而不是抛出对象(与 PHP 5 兼容)

      参数

      assertion

      断言。在 PHP 5 中,是一个用于执行的字符串或者用于测试的布尔值。在 PHP 7 中,可以是一个返回任何值的表达式, 它将被执行结果用于指明断言是否成功。

      description

      如果 assertion 失败了,选项 description 将会包括在失败信息里。

      exception

      在 PHP 7 中,第二个参数可以是一个 Throwable 对象,而不是一个字符串,如果断言失败且启用了 assert.exception 该对象将被抛出。

      实例

      将 zend.assertions 设置为 0:

      <?php 
      ini_set('zend.assertions', 0); 
      
      assert(true == false); 
      echo 'Hi!'; 
      ?>

      以上程序执行输出结果为:

      Hi!

      将 zend.assertions 设置为 1,assert.exception 设置为 1:

      <?php 
      ini_set('zend.assertions', 1); 
      ini_set('assert.exception', 1); 
      
      assert(true == false); 
      echo 'Hi!'; 
      ?>

      以上程序执行输出结果为:

      Fatal error: Uncaught AssertionError: assert(true == false) in -:2
      Stack trace:
      #0 -(2): assert(false, 'assert(true == ...')
      #1 {main}
        thrown in - on line 2

       

      以上就是本次介绍的网站开发电子书的全部相关内容,希望我们整理的资源能够帮助到大家,感谢大家对码农之家的支持。

      上一篇:图解Java多线程设计模式

      下一篇:21天学通PHP 第2版

      展开 +

      收起 -

      下载地址:百度网盘下载
      网站开发 相关电子书
      PHP、MySQL与JavaScript学习手册(第4版)
      PHP、MySQL与JavaScript学习手册(第4版) PDF 中文高清版

      本书有借助面向对象的编程基础,深入学习PHP。研究MySQL,从数据库结构到复杂查询。掌握JavaScript语言,以及带有jQuery的增强功能。调用Ajax进行后台浏览器/服务器通信等,欢迎免费下载

      立即下载
      PHP7.0+MySQL网站开发全程实例
      PHP7.0+MySQL网站开发全程实例 PDF 完整超清版

      《 PHP7.0MySQL网站开发全程实例 》在XAMPP集成化自然环境下,应用Dreamweaver对PHP动态网站开发。《PHP7.0MySQL网站开发全程实例》以全程实例课堂教学为设计方案总体目标,从网站开发自然环境的配

      立即下载
      PHP和MySQL Web开发(第4版)
      PHP和MySQL Web开发(第4版) PDF 中文版

      《PHP和MySQL Web开发》将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子

      立即下载
      ASP.NET MVC 5 网站开发之美
      ASP.NET MVC 5 网站开发之美 PDF 高清版

      ASP.NET MVC是微软Web开发平台中最重要的一块拼图,其架构特性更适合用来开发大型的Web应用程序,且ASP.NETMVC的开发方式也越来越受到重视,因此学习MVC已是刻不容缓。 ASP.NET MVC 5 网站开发之美

      立即下载
      PHP&MySQL跨设备网站开发实例精粹
      PHP&MySQL跨设备网站开发实例精粹 PDF 超清扫描版

      这本书从易学实用的角度详细讲解了PHP、HTML5语法,MySQL数据库存取,网页之间的信息传递、表单的后端处理等,提供了丰富的网站开发范例,欢迎下载

      立即下载
      读者心得
      57小时36分钟前回答

      PHP连接MYSQL数据库的3种常用方法

      对于PHP入门用户来说,我们只要掌握基本的数据库写入、读取、编辑、删除等基本的操作就算入门,也可以写出简单的程序出来,比如留言本、新闻文章系统等等。在整个过程中,MySQL数据库的连接也是比较重要的,可以使用多种方法进行连接,对于新手来说我们就不要去分析哪种方式对于系统资源的优化程度,我们先能连接上就行。 这里,整理几种常用的PHP连接MYSQL数据库的方法。 第一、 常用普通方法 $mysql_server="localhost";$mysql_username="数据库用户名";$mysql_password="数据库密码";$mysql_database="数据库名";//建立数据库链接$conn = mysql_connect($mysql_server,$mysql_username,$mysql_password) or die("数据库链接错误");//选择某……

      码农之家

      余天佑 提供上传

      资源
      39
      粉丝
      38
      喜欢
      193
      评论
      1

      Copyright 2018-2021 www.xz577.com 码农之家

      版权投诉 / 书籍推广:520161757@qq.com