奥丁9
奥丁9
后端
数据库
redis
mysql
mongoDB
达梦
php
laravel
laravel-admin
dcat
表单
表格
java
spring
python
go
c
c++
前端
vue
nodejs
sass/less
html/css
前端框架
javascript
微信生态
公众号
小程序
uniapp
typescript
其他
AI
数据结构
安全
linux
seo
git
健身
算法
正则表达式
docker
待分类
后端
/
php
php笔记
2年前
aoding9
101
php
学习笔记
后端
## 1.安装配置 apache ### 1.1进入官网下载 - http://httpd.apache.org/   最新版是2.4.46,点击之后,下载Windows版本  ### 1.2 下载Windows发行版 - 这里说项目不提供二进制版本,只有源码,如果不能自己编译,可以从网上发行版中获取。,下面有一些推荐,随便选一个进去下载 - https://www.apachehaus.com/cgi-bin/download.plx  ### 1.3 解压 - 解压到d盘server文件夹下 - 直接运行bin/httpd.exe不行,查看readme.md帮助文件后,得知要修改一些地方  ### 1.4 修改安装目录配置 - 默认是应该装在c:/Apache24目录,其他目录需要修改/conf/httpd.conf配置文件 - SRVROOT配置项的值改为d:/server/apache24(解压时的目录) ### 1.5 安装为Windows服务 - 为了方便使用,打开cmd,进到bin目录,输入httpd -k install将其安装为Windows服务 - 可以加-n修改服务名称 ### 1.6 启动服务 - 可以输入services.msc打开服务管理器启动,也可以输入net start apache2.4启动  - 也可以进到Bin目录,双击ApacheMonitor.exe启动,这个是监控程序,会在任务栏创建小图标方便使用  ### 1.7浏览器浏览 浏览器输入http://localhost(默认的本地地址),ok  ### 1.8相关命令 - httpd 用来查看Apache具有哪些功能以及配置文件是否有错 - httpd -t 验证配置文件是否正常 - httpd -M 查看当前加载哪些模块(静态加载static和动态加载shared)  ### 1.9 配置默认站点 在httpd.conf中修改apache配置,配置完成后要重启apache服务才能生效 - 修改网站根目录:DocumentRoot 默认在安装目录/htdocs ``` DocumentRoot "网站根目录" ```  - 起别名:Servername(端口可以带也可以不带,默认80) ``` ServerName localhost ``` - 监听哪个端口:Listen ``` Listen 80 ``` ### 1.10修改hosts文件 - 打开C:\Windows\System32\drivers\etc\下的hosts文件,添加一行127.0.0.1 localhost,让localhost解析到127.0.0.1(也就是本地) ``` 127.0.0.1 localhost ``` ## 2.安装配置php ### 2.1 官网下载php - 打开官网www.php.net,点最上方downloads按钮,再点Windows版本的下载。一步到位下了最新的php8版本。如果要搞就旧版以后再弄吧。 - 注意要下载下面那个thread Safe版本,上面那个没有php8apache2_4.dll文件,别问我没啥知道(/ ^ \ ) -   ### 2.2解压 - 解压到/server/php8 - 注意要有php8apache2_4.dll这个文件,没有的话是版本下错了  ### 2.3 编译试试 - 在安装目录打开cmd输入php.exe -f PHP文件所在路径尝试编译一下,新建11.php随便输点内容,成功  ### 2.4 配置apache加载php模块 - httpd.conf里面修改下 ```httpd.conf # 1.加载php模块 LoadModule php_module 'D:/server/php8/php8apache2_4.dll' # 2.php配置文件路径(默认就是php安装目录) PHPIniDir D:/server/php8/ # 3.让apache分配工作给php,后缀为php和html的文件给php模块解析 AddType application/x-httpd-php .php .html ``` - php.ini文件默认不存在,以development和production开发版和生产版存在,我们复制一个重命名为php.ini作为默认配置文件 - LoadModule 后面的php_module好像不能写错,我加了个8就出问题了 - 改完重启apache - 在htdocs目录新建一个php文件,随便输点内容,打开浏览器发现正常  ## 3.mysql ### 3.1 开官网下载 - 打开https://www.mysql.com - 点击downloads  - 再点MySQL Community (GPL) Downloads社区版下载,找不到可以搜索Community字样  - 选Windows版  - 选离线安装包  - just start my download开始下载(5.5.21才几十mb,8.0.22要四百多。。。额,算了先装吧  ### 3.2 双击安装 - 自定义安装  - 下一步,选择安装服务端和数据可视化界面  - 等待安装,然后下一步 - 进行配置,记得勾选防火墙端口放行  - 选强密码(下面那个是兼容mysql5.x)  - 输入root密码(b1密码,首字母大写)  - 配置服务(图片里面勾选了开机启动,不过我给他取消了)  - 应用配置,等待完成  - 配置其他产品,由于此处只有mysql server需要配置,所以就结束了  ### 3.3 配置系统环境变量 右键我的电脑,属性,高级系统设置,环境变量,path,新增一行 `C:\Program Files\MySQL\MySQL SERVER 8.0\bin` 如果没有就加,有的话不用加  ### 3.4 启动mysql服务 cmd输入net start MySQL80 需要管理员身份运行cmd才行  ### 3.5 修改数据存储路径 - 1 关闭mysql服务 - 2 在其他地方建个文件夹 - 3 打开C:\ProgramData\MySQL\MySQL Server 8.0\my.ini(不是安装目录)进行修改 `datadir=D:/ProgramData/MySQL/MySQL Server 8.0\Data`  - 4 将原来“C:/ProgramData/MySQL/MySQL Server 8.0”路径下的Data文件夹(勿删)复制到“ D:/ProgramData/MySQL/MySQL Server 8.0”中(其他路径也行)。 ### 3.6 cmd使用mysql - 打开cmd,启动服务net start mysql80 - 输入mysql -uroot -p回车,输入密码,成功进入mysql命令行  - 输入exit;退出(要带上英文分号) ### 3.7 相关说明 mysql客户端访问服务端需要进行寻找匹配,连接认证 #### 连接: 要连接的IP和端口(本地可以省略) -h主机ip(中间没有空格) -P端口 #### 认证 输入密码时直接回车,可以输入密文密码 -u用户名 -p密码 ### 3.8 php连接MySQL数据库 php本身不具备操作mysql数据库的能力,需要借助相关扩展来实现 - 1.php.ini文件中加载mysql扩展 - 和视频里面不同的是,新版中php_mysql.dll已经舍弃,现在是用php_pdo_mysql.dll和php_mysqli.dll(i为增强的意思) - [PDO和MySQLi区别](https://www.cnblogs.com/wanglijun/p/9458890.html) 貌似pdo更好,不过mysqli和原版mysql比较像,出于视频教程考虑,干脆俩个都加载进来,后面再看情况吧  - 添加扩展路径,因为php是被apache加载,相对路径换了,这里给他绝对路径 `extension_dir = 'php扩展包存放的绝对路径'`  - 设定php时区 ```*; 设置系统时区(中国的时区* date.timezone = PRC ``` - 重启apache,网站根目录创建个php文件,使用phpinfo()环境函数看有没有加载mysqli和pdo_mysql   ## 4.配置虚拟主机 实现一台主机上部署多个网站,一个文件夹就是一个网站,让用户根据不同网站读取不同文件夹的内容 ### 4.1 分类 - 基于ip(多个网卡就有多个ip了 - 基于域名,同一个ip但是不同域名 ### 4.2 搭建 - 方式1:主配置文件中,手动开启虚拟主机(不推荐) ``` NameVirtuaHost *:80 ``` - 方式2:在专门的虚拟主机配置文件中配置 - 主配置文件中加载虚拟主机配置文件 ``` # Virtual hosts 开启虚拟主机 Include conf/extra/httpd-vhosts.conf ``` - 虚拟主机配置文件中开启虚拟主机(在extra/httpd-vhost.conf) 进行各种配置 - 由于用的新版,有些地方不同了 - 比如Order Deny Allow被Require替代(可以用mod_access_compat兼容旧写法) - DirecttorIndex要用IfModule指令才可以 - 分号;注释不行,必须用# ``` <VirtualHost *:80> # 1网站根目录 DocumentRoot "D:/php2021/code/1-php-env" # 2主机名 ServerName 111.com # 3增加域名解析 改hosts # 4配置网站目录访问权限 <Directory "D:/php2021/code/1-php-env"> # 设定方式:代表匹配权限的顺序 #Order Deny,Allow # 禁止访问的范围 #Deny from all #允许访问的范围 #Allow from all # 由于顺序执行,先禁止所有,再允许所有,结果是允许所有 # 即时后面再加deny,但是order中设定是allow就结束,所以不会再去解析 # Deny from all # 5 配置访问列表 # 当访问一个目录时,并且没有指定访问哪个文件,时是否列表显示文件列表(生产环境需要禁用掉) Options Indexes FollowSymLinks # 6 访问目录时指定默认文件 # DirectorIndex index.html index.htm index.php # 新版要写成这样 # 注意apache2.4不是用deny了而是require # 拒绝所有 #Require all denied #允许所有 Require all granted <IfModule dir_module> DirectoryIndex index.html index.htm index.php </IfModule> </Directory> </VirtualHost> ``` - 这个地方,后面有空再详细学一下新版如何配置吧 ### 4.3 添加虚拟主机 - 刚刚百度了一下,指定VirtualHost详细域名或ip后,ServerName可以省略 - AllowOverride None表示禁用.htacess配置文件 ``` <VirtualHost 222.com:80> DocumentRoot "D:/php2021/code/1-php-env/orther-host" <Directory> Options Indexes FollowSymLinks Require all granted # 忽略.htacess配置文件 AllowOverride None <IfModule dir_module> DirectoryIndex index.html index.htm index.php </IfModule> </Directory> </VirtualHost> ``` - 修改配置文件后,还需要修改Hosts文件,然后重启apache - 为了方便后面使用,我把根目录改为code文件夹 ``` <VirtualHost loc.com:80> DocumentRoot "D:/php2021/code/" <Directory "D:/php2021/code/"> Options Indexes FollowSymLinks AllowOverride None Require all granted <IfModule dir_module> DirectoryIndex index.html index.htm index.php </IfModule> </Directory> </VirtualHost> ``` ## 1标记/注释/结束符 ```php+HTML <!-- php标记 --> <!-- 1 ASP标记和短标记 以前的 不推荐 --> <!-- 需要apache配置开启short_open_tag=On asp_tags=On --> <!-- <% echo 'asp<br>'; %> --> <!-- < ? echo 'short_tag<br>' ; ?> --> <!-- 2 脚本标记 --> <!-- <script language="php"> echo 'script tag<br>'; </script> --> <!-- 3 标准标记 推荐--> <?php // 结尾用分号分隔 // ? >自带分号作用,可以省略最后一行分号 echo 'standard tag<br>'; echo 'hello php<br>' ?> <!-- 如果省略 ? > 那么最后一行不可以省略分号 --> <?php // 行注释 /* 块 注 释 */ ``` 2 ## 2 变量 ### 2.1定义 - 用于存储数据 - 存在名字 - 可以通过名字来访问数据 - 可以改变数据 ### 2.2使用 ```php <?php // 定义变量 $a; // 变量赋值 $b = 111; // 访问变量 echo $b; // 修改变量 $b = 222; echo $b; // 删除变量 unset($b); echo $b; ```  ### 2.3 变量命名规范 ```php // 命名规则: // 必须以$符号表示变量 // 名字可以包含英文数字下划线,但不能以数字开头 // php允许中文变量,但不推荐 $aa11_; // $1a_; $水果 = '苹果'; echo $水果; ```  ### 2.4 预定义变量 系统提前定义的变量,都是数组。 - **$_GET**: 获取所有表单以get方式提交的数据 - **$_POST**: 获取所有表单以post方式提交的数据 - **$_REQUEST**: 获取所有表单以get和post方式提交的数据 - $GLOBALS: php中所有全局变量 - **$_SERVER**: 服务器信息 - **$_SESSION**: session会话数据 - **$_COOKIE**: cookie会话信息 - $_ENV: 环境信息 - $_FIELS: 用户上传的文件信息 ``` // 提前定义的变量,系统定义的,都是数组。 // $_GET $_REQUEST $GLOBALS等等 $水果='苹果' echo $GLOBALS['水果']; // 前面在全局下定义了一个$水果='苹果' ``` ### 2.5 可变变量 如果变量保存的值就是另一个变量的名字,那么可以通过访问一个变量得到另一个变量的值 - 在变量前面加一个$符号(我愿称之为套娃变量) ```php // 一个变量的值是另一个变量的名字,通过访问这个变量得到另一个变量,前面需要加$符号,简称套娃 $a1 = 'a2'; $a2 = 'a3'; $a3 = 'a1'; echo $a1; echo $$a1; echo $$$a1; echo $$$$a1; ``` 结果:  ### 2.6 变量传值 - 值传递 - 将一个变量保存的值复制一份,再赋值给另一个变量 - 两个变量没有关系,修改一个不影响另一个 - 引用传递 - 直接把一个变量的内存地址赋值给另一个变量 - 两个变量的值都是同一个,修改这个变量,那个变量也跟着变 - 变量前面加&符号,表示引用传值 ```php // 5变量传值 $aaa = 111; // 值传递 复制变量的值之后再赋值给另一个变量,互相不影响 $bbb = $aaa; // 引用传递 复制变量值的内存地址之后再赋值给另一个变量,指向同一个内存空间,互相影响 $ccc = &$aaa; $aaa = 222; echo $aaa, $bbb, $ccc; ```  ## 3 常量 - 指程序运行中不可改变的数据 - 一旦定义,通常不可修改(用户级别 ### 3.1 定义方式 - define('常量名',常量值) - 5.3之后才有的: const 常量名 = 常量值 ```php // 定义方式1 define('PI', 3.14); // 定义方式2 const PI2 = 3.1; // define可以定义常量,可以使用特殊符号常量 define('^_^', 'smile'); // const不可以 // const ^_^ = 'smile'; ``` - define和const的区别:访问权限不同 - 常量通常不区分大小写,但是可以区分,需要在给define()传递参数时指定大小写敏感为true > **define** ( string `$name` , [mixed](mk:@MSITStore:D:\学习资料\php入门到精通教程\黑马PHP-28天-零基础新手入门教程-代码笔记课件-12863134-15525720-15351498\黑马PHP全阶段资料-无数_mirage\php7_enhanced_zh.chm::/res/language.pseudo-types.html#language.types.mixed) `$value` [, bool `$case_insensitive` = false ] ) : bool ### 3.2 使用 ```php // 直接写常量名 echo PI; // 如果使用有特殊符号名字的常量,需要用访问常量的函数 echo constant('^_^'); ``` ### 3.3 何时使用常量 - 可能变化的用变量 - 不变化的,都可以用,变量居多,因为可以自动回收内存 - 数据不允许修改的,用常量 ### 3.4 系统常量 系统定义好的常量 几个常用系统常量: - PHP_VERSION: php版本号 - PHP_INT_SIZE: 整形大小 - PHP_INT_MAX: 整形最大值 ```php // 系统常量 echo '<br>', PHP_VERSION, '<br>', PHP_INT_SIZE, '<br>', PHP_INT_MAX; ```  ### 3.5 魔术常量 系统定义的一些特殊常量,开头结尾都是双下划线,类似这种:\__XXX__,值会跟着环境变化,但是用户无法修改 - \__DIR__ 当前被执行的脚本所在电脑绝对路径 - \__FILE__ 和 _\_DIR__差不多,但是带上自己文件的名字 - \__LINE__ 执行到当前位置的代码行数 - \__NAMESPACE__ 命名空间 - \__CLASS__ 类 - \__METHOD__ 方法 ## 数据类型 php是弱类型语言,变量本身没有数据类型 ### 4.1 8种数据类型 3大类8小类 - 简单数据类型:4小类 - 整形(int/integer) - 根据系统环境不同,一般是4个字节或者8字节,二进制码第一位表示正负号,超出范围的整数会自动转成浮点数 - 浮点型(float/double) - 8字节或16字节 表示小数或者整形存不下的整数,二进制码第一位是正负号,跟着7位表示乘以10的几次幂,后面位数为科学计数法的因数,两者的乘积就是浮点数据的值。因数是由原数值不断除以2得到的,有精度限制,当出现因数位数过长,或者除不尽的时候,位数超过了精度,多出的尾部会被省略掉,导致结果可能不准确。 - 字符串型(string) - 系统根据实际长度分配,存放字符组成的字符串 - 布尔型(bool/boolean) - 布尔值,真和假:true和false - 复杂数据类型:2小类 - 对象类型: object - 面向对象 - 数组类型: array - 存储多个数据 - 特殊数据类型:2小类 - 资源类型(resource) - 存放资源数据,如数据库、文件等 - 空类型(NULL) - NULL类型的值就是NULL,不可以运算 ### 4.2 类型转换 将数据的类型转成另一种 - 两种转换方式 - 自动转换(系统自动判断的) - 强制转换(手动,效率高) - 其他类型转数值 - 布尔true为1,false为0 - 字符串以字母开头的永远为0,以数字开头的,取碰到字符串为止  ```php <?php $a = 'abc11'; $b = '1.1.1abc'; // 自动类型转换 // 布尔值true自动转为1 echo true + 1; // 手动类型转换 // php7为了提高性能,移除了一部分自动类型转换,现在这么加不会自动转了 // echo $a + $b; // 变量前面加括号,里面写要转换的类型 echo (float)$a + (float)$b, '<br>'; echo intval($a) + intval($b), '<br>'; // 结果为1.1和1,$a转成0,$b转成了1以及1.1 // 判断数据类型 // 布尔类型不能用echo查看,可以用var_dump输出类型和值 // is_datatype 可以判断是否为某个类型,结果为布尔值 var_dump(is_int($a)); var_dump(is_string($b)); // gettype获取变量的类型 echo gettype($a), '<br>'; // settype设置变量的类型,如果设置成功会返回true var_dump(settype($b, 'int')); echo '<br>', gettype($b), $b; // 强制转换和settype的区别 // 强制转换是对数据复制后转换,不影响原来的数据,settype是直接对原数据转换 ``` ### 4.3 数据类型更多介绍 #### 整数类型 ```php // php有四种整形进制定义 // 十进制 $a1 = 110; // 二进制 0b开头 $a2 = 0b110; // 八进制 0开头 $a3 = 0110; // 十六进制 0x开头 $a4 = 0x110; echo $a1 . '<br>' . $a2 . '<br>' . $a3 . '<br>' . $a4 . '<br>'; // echo自动输出十进制整数 ```  #### 浮点类型 ```php // 浮点型 // 二进制码第一位是正负号,紧跟的7位是科学计数法的中10的指数,后面的是因数,二者乘积就是存储的数值 $f1 = 1.23; $f2 = 1.23e10; // 由于因数为不断除以2得到,位数超过精度时舍弃尾部,所以结果可能不准确 $f4 = 2.1; $f5 = 0.7; var_dump($f4 / 3 === $f5); // 当整形超过存储的范围后会用浮点型存储 $f3 = PHP_INT_MAX; echo gettype($f3), '<br>'; $f3 += 1; var_dump($f1, $f2, $f3); ``` #### 布尔类型 ```php // 布尔类型 // 真、假 true false // 其他类型转布尔类型时,有些地方需要注意 // empty() 判断数据的值是否为“空”,不是NULL,为“空”返回true,否则false,空字符串空数组都是true // isset() 检测变量是否已设置并且非 NULL,存在变量返回true,否则false /* empty() isset() $x; true false $x=null; true false $x=undefined true false 上面三个isset为false,其他一般为true $x=0; true $x="0"; true $x=false; true $x="false"; false 布尔值false为empty为true,但是字符串“false”为false 数字0和字符串0都为true */ // 具体的看php手册 ```  ## 操作运算符 ### 1 赋值运算 将“=”号右边的运算结果保存到内存中,然后将结果的内存地址保存给左边的变量或常量 ### 2算术运算符 +-*/%加减乘除 取余 /和%的被除数不能为0 ```php $b = 1 % 0; // error ```  ### 3 比较运算符 ```php // 比较运算符 // == === != !== >= <= // ==类型可以不同 ===类型也要相同 var_dump(1 > 2); // false var_dump(1 == "1"); // true var_dump(1 === "1"); // false ``` ### 4 逻辑运算符 ### 5 连接运算符 ### 6 错误抑制符 ```php <?php // 逻辑运算符 // && || ! 与或非 $a = true; $b = false; var_dump($a && $b); // false a与b都要true才true var_dump($a || $b); // true a或b有一个为true则为true var_dump(!$a); // false 取反,非true为false // 逻辑与和逻辑或被称为短路运算,如果前面的表达式满足条件,后面可能就不会继续执行,所以把出现概率最大的表达式放在前面,提高效率 // 连接运算符 // . 对左右两边做字符串拼接,得到一个新的字符串 $c = '<br>' . $a . $b; echo $c; echo gettype($c); // .= 复合运算,将左边和右边连接起来,再赋值给左边 $a .= $b; //相当于 $a = $a.$b; echo '<br>'; // 错误抑制符 // @符号 // 在可能出错的表达式前面添加@符号,通常用于生产环境阻止用户看到报错 // echo ($a / 0); // 报错 echo (@$a / 0); // 不报错 ``` ### 7 三元运算 ```php // 表达式1?表达式2:表达式3 // 如果表达式1为true,则执行表达2,否则执行表达式3 // 可以嵌套 echo '1>0?'; echo 1 > 0 ? 'yes' : 'no'; ``` ### 8 自操作运算符 ```php // 自操作运算符 // ++ -- 自增自减,可以前置或者后置 // 需要注意的是,++$a和$a++有一定差异,前置是先自增,再参与其他运算,后置自操作先把自己的值保留一份给别人去参与运算,自己再改变,可以理解为先运算后自操作 $a = 1; $b = $a++; // a先赋值给b,然后再加1变成2 ,b为1 $a = 1; $c = ++$a; // a先加1,然后赋值给c, c为2 echo $a, $b, $c; // 衍生 // += -= *= /= %= 类似自操作,左边与右边先运算,再赋值给左边 ``` ### 9 位运算符 #### 9.1计算机码 计算机存数据时用二进制规则,计算机码左边第一位是符号位,正数为0,负数为1 - 原码:数据本身从十进制转成二进制 - 正数 符号位为0 - 负数 符号位为1 - 反码:正数反码为本身,负数的反码是,符号位不变,其他位取反 - 补码:正数补码是本身,负数的补码是反码+1(实际是模-|原码| 模减原码的绝对值,为了方便计算机计算,所以先让他求反码) - 0的反码和补码都是0000 0000 -128(-0)补码为1000 0000,他比较特殊,是人为规定的,没有原码和反码(因为原码只能表示+0~127和-0~-127) - 为什么要用反码和补码,怎么来的? 简单来说,加法电路比减法电路更简单,为了简化计算机基础电路设计,要让减法转换为加法,当舍弃溢出进位时,减去这个数,等于加上这个数的同余数,这个同余数就是补码(模:计数系统的状态数,补码=模-|原码绝对值|)。不过为了方便计算机计算,转换为先求反码再+1)。 > 所谓原码就是机器数,是加了一位符号位的二进制数,正数符号位为0,负数符号位为1,计算机中存储、处理、运算的数据通常是8位、16位、32位或64位的,这里以最简单的8位为例讲解。注意符号位是包含在8位中的其中1位,故可直观读出的数只有7位(只有后7位数可以按权展开)。有心人可能注意到原码是有缺陷的,它只能表示255种状态,因为00000000(+0)和10000000(-0)其实是一个数,因此原码的表示范围成了-127到+127,这个问题需要神奇的补码来解决,因为在补码中10000000被用来表示-128。 > > 所谓反码,英语里又叫ones' complement(对1求补),这里的1,本质上是一个有限位计数系统里所能表示出的最大值,在8位二进制里就是11111111,在1位十进制里就是9,在3位十六进制里就是FFF(再大就要进位了)。求反又被称为对一求补,用最大数减去一个数就能得到它的反,很容易看出在二进制里11111111减去任何数结果都是把这个数按位取反,0变1,1变零,所以才称之为反码。用原码求反码的方法是,正数不变,负数保留符号位1不变,剩下位按位取反。 > > 所谓补码,英语里又叫two's complement(对2求补),这个2指的是计数系统的容量(模),就是计数系统所能表示的状态数。对1位二进制数来说只有0和1两种状态,所以模是10也就是十进制的2,对7位二进制数来说就是10000000,这个模是不可能取到的,因为位数多一位。用模减去一个数(无符号部分)就能得到这个数的补,比如10000000-1010010=0101110,事实上因为10000000=1111111+1,稍加改变就成了(1111111-1010010)+1,所以又可以表述为先求反再加1。总结求补码的方法就是正数依旧不变,负数保留符号位不变,先求反码再加上1。 https://zhuanlan.zhihu.com/p/91967268?utm_source=wechat_session https://www.zhihu.com/question/20159860 https://blog.csdn.net/qq_24601199/article/details/78724137 https://www.zhihu.com/question/20159860 视频: https://www.bilibili.com/video/BV1HJ411c7SS  - 涉及到同余,莫有学过。。。 - 图形理解 把数据想象成表盘,表盘顺时针转为加法,逆时针转为减法,要把6转到4,可以-2也可以+10,也就是说,-2的操作可以用+10代替,同样的,-1也可以用+11代替。 原码转为反码,也就是把-2转成+10进行计算,从而得到正确结果4。  补码:为什么负数计算时要 +1转成补码?并且计算结果仍然正确? 使用反码后,符号位参与运算,导致出现+0和-0两个0。为了保持0的唯一性,负数反码+1变成补码。 负数反码+1。 - 通过下图可以发现,带符号整数与不带符号整数具有一一对应的关系,求带符号数的加法,可以看成求不带符号数的加法。 - 为了避免-0,负数区间整体-1。  #### 9.2 位运算符 对计算机中的最小单位bit位进行运算 - &:按位与,两个都为1,结果为1,否则为0 - |:按位或,两个钟有一个为1,结果为1,否则为0 - ~:按位非,一个位,如果为1,结果为0,如果为0,结果为1 - ^:按位异或,两个相同则为0,不同则为1 - <<:按位左移,bit位整体左移一位,右边补0 - \>>:按位右移,bit位整体右移一位,左边补符号位,正数补0,负数补1 ```php <?php $a = 5; $b = -5; var_dump($a & $b); // 1 /* 按位与 首先取出系统存储的数值,然后判断符号位,进行转码 原码:第一位为符号位,参与运算 5 -> 0000 0101 -5 -> 1000 0101 反码:正数反码不变,负数反码符号位不变,后面按位取反 5 -> 0000 0101 -5 -> 1111 1010 补码:正数补码不变,负数反码+1 5 -> 0000 0101 -5 -> 1111 1011 计算机进行位运算都是采用补码进行运算 ,运算结束后需要转成原码才是要显示的结果 0000 0101 & 1111 1011 = 0000 0001 结果为1 */ var_dump(~$a); echo '<hr>'; /* 按位非 正数反码补码是本身,按位非之后,补码符号位为1,要-1还原为反码,再还原为原码 0000 0101 ~ 1111 1010 -1 1111 1001 = 1000 0110 结果为-6 */ var_dump($b << 1); // -10 var_dump($b << 2); //-20 var_dump($b << 3); // -40 var_dump($b << 4); //-80 echo '<hr>'; /* 按位左移1位和2位 补 1111 1011 <<1 1111 0110 <<2 1110 1100 反 1111 0101 1110 1011 原 1000 1010 1001 0100 十进制 -8+-2= -10 -16+-4= -20 */ var_dump($b >> 1); // -3 var_dump($b >> 2); // -2 var_dump($b >> 3); // -1 var_dump($b >> 4); // -1后面都是-1。为啥?看下面 /* 按位右移1位 补 1111 1011 >>1 1111 1101 >>3 1111 1111 >>4 1111 1111 反 1111 1100 1111 1110 同 原 1000 0011 1000 0001 十进制 -2+-1= -3 -1 -1 */ // 按位左移:可以看做补码乘以2 // 按位右移:类似补码除以2的操作,但不完全正确 ``` ## 10 运算符优先级和结合方向 ### 10.1 是啥 - 运算符优先级:指定了两个表达式绑定得有多"紧密",如1*2+3会先计算1\*2,再算2+3,因为\*比+优先级更高,优先计算出结果 - 结合方向:当运算符优先级相同时,结合方向决定了先从哪边开始计算,如2+3+4,结合方向为左,从左开始,先算2+3,再算5+4。 - **没有结合方向的,相同优先级运算符不能连在一起使用,如:1<2>3** ### 10.2 从高到低优先级 大部分的: - 一元运算符 》二元运算符 》三元运算符 - 算数运算 》 比较运算 》 位运算 》 逻辑运算 》 赋值运算 - 长得比较像的通常在一起,比如>>和>=,&和&& - 带有赋值运算的复合运算优先级很低 - 比较运算没有结合方向 几个比较常用的 | 类型 | 运算符 | 结合方向 | | -------- | --------------------------------------------- | -------- | | 自增自减 | ++ -- | **右** | | 逻辑运算 | ! | **右** | | 算数运算 | */% 高于 +- | 左 | | 位运算 | \>> << | 左 | | 比较运算 | < <= > >= 高于 == != === !== <> <=> | ***无*** | | 位运算 | & 高于 ^ 高于 \| | 左 | | 逻辑运算 | && 高于 \|\| 高于 | 左 | | 三元运算 | ? : | 左 | | 赋值运算 | = += -= *= **= /= .= %= &= \= ^= <<= >>= | **右** |  需要加快速度了,笔记改为php里面注释记,不单独记了。 ## 流程控制 和js差不多 ### 1 顺序结构 默认从上往下执行 ### 2 条件结构 if elseif else switch ### 3 循环结构 #### 3.1 for ```php // 基本用法 // 第一个表达式:初始化条件,可以有多个语句,用逗号分隔,在第一次循环开始前执行 // 第二个表达式:边界判断,用于终止循环,在每次循环开始前执行 // 第三个表达式:改变循环变量,在每次循环结束后执行 for ($i = 0; $i < 10; $i++) { echo $i; } // 特殊用法 $ii=1; // 省略for后面的表达式,会无条件执行代码块 for(;;){ // 在代码块里面手动进行初始化、边界判断、改变变量,否则会死循环 echo $ii++; if($ii>10){ break; // 终止循环 } } // 边界条件有时需要动态获取,所以把他用变量表示,同时初始化时获取到值,以免重复获取 // 假设这里10是动态的无法预先知道多少,初始化时赋值,只需要执行一次,如果判断时获取。每次都要去获取 for ($i = 0, $end = 10; $i < $end; $i++) { echo $i; } ``` #### 3.2 while ```php // 先判断条件,再决定是否执行 $b = 1; while ($b < 10) { echo $b; // 必须要改变循环的变量,否则会死循环,卡住 $b++; } ``` #### 3.3 do while ```php //和while差不多,但是会先执行一次,在判断条件,至少执行一次 $c = 1; do { echo $c; $c++; } while ($c < 10); ``` ### 4 流程控制替代语法 php中经常嵌套html使用,由于还要嵌套for、if等等,有很多"{"和"}",导致阅读不方便,容易搞混 所以出了一种替代语法,{用:冒号代替,}用endxxx代替,xxx指的流程控制关键字比如endfor endif 等 ```php <table border="1"> <!-- 第一次for是普通写法 --> <?php for ($i = 1; $i < 10; $i++) { ?> <tr> <!-- 第二次for使用替代语法 --> <?php for ($j = 1; $j <= $i; $j++) : ?> <td> <?php echo $i . '*' . $j . '=' . $i * $j ?> </td> <?php endfor ?> </tr> <?php } ?> </table> ```  ## 1 文件包含 https://blog.csdn.net/qq_36324472/article/details/110133609 ### 1.1 是啥 在一个php脚本文件中包含另一个php文件 ### 1.2 有啥用 - 向上包含(把朋友的东西给自己用):使用被包含文件中的内容,比如变量、函数等等,实现代码复用,一般在上面引用,叫向上包含 - 向下包含(把自己的东西给朋友用):将自己的变量函数等等,分析给被包含的文件,,一般在下面引用,叫向下包含 - 分工协作,利于维护和阅读 ### 1.3 怎么用 包含两大种,4小种 - include - include_once - require - require_once 带有once的,系统会自动判断是否已经包含过,不重复包含 ```php <?php // 向上包含,使用上面包含文件中的内容 include '1-aa.php'; // 另一种写法 // include(文件路径) echo $a; $b = 2; // 向下包含,先把自己的内容给下面包含的文件使用 require '1-bb.php'; // include和require区别 // include包含文件出错,错误级别为Warning,不影响后面继续执行 include '1-cc.php'; // require包含文件出错,错误级别为error,后面代码不会执行 require '1-cc.php'; // 不过我这个都是报的warning,可能是新版本或者配置不同导致的 ``` #### 文件加载原理: 系统将被包含内容嵌入到包含关键字所在位置,类似于复制过来了(魔术常量例外,仍然是原来文件的信息) 但是和直接写一起有区别:被包含文件单独编译,加载到内存中 #### php代码执行过程: - 读取php文件 - php编译为字节码(opcode) - zend engine解析opcode,按照字节码进行逻辑运算 - 转换为html代码 ## 2 函数 ### 2.1 是什么 函数function时一种语法结构,将实现某个功能的代码块封装到一个结构中,从而实现代码复用 ### 2.1 作用 代码复用,一般一个功能一个函数, ### 2.2 语法 ```php function 函数名([参数]){ 函数体 [return 返回值] } ``` ### 2.3 注意 ```php <?php // 1.如果函数定义时有形参,那么调用时需要传实参 function aaa($a) { echo $a; return __FUNCTION__; // 魔术常量,返回当前函数名 echo 'return关键字除了返回值,还表示函数运行结束,下面的代码不会执行'; } // 2.如果函数体(花括号中间这部分)定义了返回值,那么外面可以接收到,如果没有返回值,系统默认返回NULL $b = aaa(1); var_dump(aaa(1)); // 如果没有写返回值,默认返回NULL echo $b; // 3.函数执行是在代码执行阶段,执行到函数调用的那一行才去内存中进行调用,不是在编译阶段,所以可以在函数定义之前写调用代码(因为已经编译好了) ``` ### 2.4.函数命名规范 - 驼峰法 showInfo - 下划线法 show_info - 命名要有具体意义,尽量看名字就大概知道这个函数的功能,不要乱写,比如showInfo不要写成si等意义不明的东东 - 一个脚本周期中不能有两个同名函数 ### 2.5 关于参数 - 作用:1.使用外部变量 2.动态地执行函数,根据不同参数,得到不同结果 - 形参:在函数定义时,并没有实际参数,所以用形参代替实参,在执行时用于接收实参 - 实参:函数执行时,实际参与运算的参数,运算之前系统会把实参赋值给形参 - 形参数量要小于等于实参,如果定义时有3个形参,但是执行只传了2个实参,会报错(没有默认值的情况下),但是实参数量可以大于形参,多出的实参不会导致报错 - 默认值:定义函数时给形参设置默认值,如果没有传对应的实参,那么会用默认值代替(一般用于实参值很大可能是这个,但是又可能会变化的情况) ### 2.6 执行过程 - 系统调用函数时,先去内存寻找是否有这个函数 - 系统在栈区开辟内存空间运行函数 - 先查看函数是否有形参 * 在判断调用时是否传了对应的实参 - 默认将实参赋值给形参 * 执行函数体 * 将函数返回值返回出去(如果有返回的话) ```php // 多个参数 // 这里有2个形参 function addition($a, $b) { return $a + $b; } // 只有传了1个实参,第二个实参没有实际值,导致报错 // echo addition(1); // 这里有3个实参,第三个虽然没有形参接收,但此时有没有这个多余的参数都不会导致函数体出错 echo addition(1, 2, 3); echo '<br>'; // 默认值 // 定义时就给形参初始值,调用时如果不传入,就会使用初始值,如果传实参,则会覆盖初始值 // 注意:默认值必须放在最右边,不能左边有右边没有,错误案例:function subtraction($a=1, $b) function subtraction($a=1, $b=2) { return $a - $b; } echo subtraction(2); ``` ### 2.7 引用传递 通常情况,实参赋值给形参是简单值传递,即将实参的值复制一份,然后将复制的值赋值给形参,改变形参并不会影响实参 如果希望函数内部修改形参可以影响到实参,就可以用 ``&$变量名``,将实参的内存地址赋值给形参,二者会指向相同的内存地址,从而互相影响 - 引用传递时,&符后面必须是变量(不能是常量等) ### 2.8 函数体、return {}之间的内容就是函数体,可以进行各种操作 通过return关键字给出返回值,将他返回到函数调用的位置 - return表示函数结束,后面的代码不会执行 - return在被包含文件中使用,可以将某些东东返回给声明文件包含的位置,同时被包含文件终止执行 ### 2.9 作用域 作用域:变量、常量能够被访问的区域,能够起作用的区域 一般每个函数都有自己独立的局部作用域 - 全局变量:在最外面,用普通方式定义的变量,所属全局空间,php中只允许在全局空间使用,一般函数内部不可以访问,生命周期为脚本周期(脚本执行完才销毁) - 局部变量:在函数体内定义的变量,默认作用域就是当前函数,只有当前函数内可以使用,函数外部无法访问,生命周期为函数周期(函数执行完就销毁,可以特别处理后保留) - 超全局变量:系统定义的变量(预定义变量$\_SERVER $\_POST等)没有访问限制,哪里都可以用 ### 2.10 global关键字 如果要让局部和全局都可以访问某个变量,除了使用超全局变量,以及参数引用传值之外,还可以通过global关键字 global关键字可以在函数内部声明变量,此变量如果在函数外有全局同名变量,则自动指向全局变量,如果没有同名的,则在外部自动声明一个同名全局变量,并且内外两个变量都是指向同一个内存空间。本质就是声明全局和局部同名变量,并且保存相同内存地址。 语法:global 变量名; - global声明时不能赋值 ```php $g = 1; function g() { global $g; $g = 3; // 这里修改g,外面也被修改了 global $g2; //外面没有g2,自动声明一个全局g2 $g2 = 2; } g(); echo $g; echo '<br>'; echo $g2; // 一般不会这么用,而是用参数形式,或者常量(常量没有访问限制) ``` ### 2.11 static静态变量 - 静态变量(static):仅在在函数作用域内存在,当程序执行到离开作用域后,静态变量没有销毁,之后再进入该函数作用域时,可以继续使用上次执行后保留的值。 - 一般用于函数执行次数的统计,以及递归时,根据递归次数,执行不同代码。 ```php function count1() { $i1 = 0; // 普通局部变量,函数执行完销毁,相当于每次重新赋值为0 echo $i1++; echo '-'; static $i2 = 0; // static静态变量,函数执行完没销毁,下次执行不会重新赋值,而是使用上次的值 echo $i2++; echo '<br>'; } echo '<hr>'; count1(); count1(); count1(); ``` - 系统编译时就对static变量初始化赋值了,函数调用时,自动跳过static这一行,没有重新赋值 ### 2.12 可变函数 类似可变变量,使用变量保存函数的名字,然后$变量();调用对应的函数。一般在回调函数里面用的比较多。 ### 2.13 回调函数 可变函数一般用于回调函数,意思是函数执行到某一步,再去调用另外的函数,并且这个函数是作为参数传进去的 ```php // 可变函数 function add() { echo 1 + 2; } // 用变量保存函数的名字 $myFunc = 'add'; // 然后调用 $myFunc(); echo '<hr>'; // 回调函数 // 一个函数内调用另一个函数,并且这个函数是通过参数传进来的可变函数。 function callBack($func1, $func2) { // 使用callBack时,自动调用传进来的函数,由于代码顺序执行,当回调函数放在最前面或者最后时,就可以通过回调函数是否执行,判断外部函数执行到哪一行了。 $a = $func1(); // func1一定会在func2前面执行,并且我们可以得到他的返回值,交给第二个回调函数去处理 // 另外,定义时如果将局部变量传递给可变函数,那么回调函数内部就可以使用这个外部函数的变量了,从而对函数结果进行自定义的处理 $b = 1; $result = $func2($a, $b); return $result; // 返回结果 } function start() { echo '开始执行了<hr>'; return 3; // 返回3,交给回调函数处理 } // 需要形参接收回调函数传过来的实参 function ended($a, $b) { echo '结束执行了<hr>'; return $a + $b; } $start = 'start'; $ended = 'ended'; // 传变量名进去,或者变量名保存给变量再传,或者用变量保存匿名函数,然后传变量也行 echo callBack('start','ended'); // echo callBack($start, $ended); ``` ### 2.14 匿名函数、闭包 ```php <?php // https://www.php.cn/php-ask-429876.html // php闭包和js闭包有一些区别 // 匿名函数Anonymous functions:没有名字的函数,定义时要赋值给变量再去使用 $func = function () { echo '我是匿名函数<br>'; }; // 由于是赋值,所以结尾要分号 // 用可变函数调用匿名函数 $func(); // 变量保存匿名函数,本质得到一个Closure对象 (闭包对象) var_dump($func); // object(Closure)#1 (0) { } echo '<br>'; /** * 匿名函数也叫闭包函数,当匿名函数赋值给变量时,php自动将表达式转换为closure类的实例对象 * 作用:闭包可以保存上下文的一些变量和值,延长其生命周期 * 特性:默认闭包不能从父作用域继承变量,一般通过use结构传递进去,默认是传clone的值,如果要完全引用,可以加&进行引用传值 * 闭包一般理解:函数内部定义匿名函数,然后通过use关键字得到父作用域的变量,接着将匿名函数返回出去。当调用外部函数时,匿名函数被返回,虽然外部函数已经执行结束,但由于匿名函数等待调用,所以use的变量不会销毁。 */ function out() { $a = 123; // 通过use,将父级作用域的变量传入匿名函数内 $closure = function () use ($a) { return $a; }; // 将匿名函数返回出去 return $closure; } // 将返回的匿名函数保存给变量,out虽然执行结束,但$a在等待匿名函数调用,没有销毁 $b = out(); echo $b(); ``` ### 2.15 伪类型 Mixed混合类型、Number数值类型,主要用于辅助查看操作手册,实际没有这种类型 ## 3 系统常用函数 ### 3.1 输出 - **print** 类似于echo,输出提供的内容,输出 `arg`。 print 实际上不是函数(而是语言结构),所以可以不用圆括号包围参数列表。 和 *echo* 最主要的区别: *print* 仅支持一个参数,并总是返回 1。 - **print_r** — 以易于理解的格式打印变量。 ```php // 输出相关 print('print:输出字符串'); echo '<br>'; echo print 'print本质是结构,可以不带括号,返回值为1。<br>'; echo '<br>'; print_r('print_r:以人类易读的格式显示一个变量的信息。 '); echo '<hr>'; ``` ### 3.2 时间 - **date()** 返回格式化后的时间,默认当前时间  - **time()** 返回unix时间戳 - **microtime()** 返回微秒数 - **strtotime()** 尝试将时间字符串转为时间戳,失败返回false,默认相对当前时间。 ```php // 时间相关 // 1.按指定格式,输出时间戳(从1970年格林威治时间开始计算的秒数)如果不指定时间,则默认当前时间戳。 // date( string $format[, int $timestamp] ) : string echo date('Y 年 m 月 d 日 H:i:s'); echo '<br>'; // 2.time() 获取当前时间对应的时间戳 echo time(); echo '<br>'; // 3.microtime() 返回当前unix时间戳和微秒数 // microtime([ bool $get_as_float] ) : mixed // 如果调用时不带可选参数,本函数以 "msec sec" 的格式返回一个字符串,其中 sec 是自 Unix 纪元(0:00:00 January 1,1970 GMT)起到现在的秒数,msec 是微秒部分。字符串的两部分都是以秒为单位返回的。 // 如果给出了 get_as_float 参数并且其值等价于 TRUE,microtime() 将返回一个浮点数。 echo microtime(); echo '<hr>'; // 4. strtotime() // 本函数预期接受一个包含美国英语日期格式的字符串并尝试将其解析为 Unix 时间戳(自 January 1 1970 00:00:00 GMT 起的秒数),其值相对于 now 参数给出的时间,如果没有提供此参数则用系统当前时间。 // strtotime( string $time[, int $now = time()] ) : int echo strtotime('10 hours'); // 返回当前时间10小时之后的时间戳 echo '<hr>'; ``` ### 3.3 数学 - max 返回参数中的最大值 - min 返回参数中最小值 - rand 得到指定区间的随机数 - mt_rand 也是随机数,不过效率比rand高 - round 四舍五入 - ceil 向上取整 - floor 向下取整 - pow 求指数幂:pow(2,8)即求2^8 - abs 求绝对值 - sqrt 求平方根 ### 3.4 函数处理 - function_exists 判断指定函数是否在内存中存在,帮助用户不去使用不存在的函数(语言结构不会返回true) - func_get_arg 从用户自定义函数的参数列表中获取某个指定的参数。 - func_get_args 返回一个包含函数参数列表的数组 - func_num_args 返回传递给函数的参数数量 ```php // 函数相关 function add($a, $b) { // 返回传入函数的参数中的某一个 echo func_get_arg(1) . '<br>'; // 返回2 // 以数组形式,返回传入函数的所有参数 var_dump(func_get_args()); // 返回[1,2,3] echo '<br>'; // 返回传入函数的参数数量 echo func_num_args() . '<br>'; // 返回3 return $a + $b; } // 判断函数内存中是否存在 var_dump(function_exists('add')); echo '<br>'; // 利用短路运算,如果函数存在才执行 function_exists('add') && add(1, 2, 3); ``` # 错误处理 代码执行时发现了错误,通过错误处理形式告知程序员 ## 1 错误分类 - 语法错误parse error - 代码书写不符合php语法,编译时不通过 - 运行时错误runtime error - 代码语法正确,但是运行时缺少某些条件,比如变量 - 逻辑错误 - 写代码时 出现逻辑性错误,代码正常执行,但结果不符合预期,比如++$a写成$a++导致结果不同,以及等于判断==写成赋值符号= ## 2 错误级别level 错误代码在php中被定义为系统常量 ### 2.1系统错误 - E_PARSE: 编译错误,语法错误 - E_ERROR: fatal error 致命错误 会在出错位置停止运行 - E_WARNING: 警告错误,不影响继续执行,但可能得不到预期结果 - E_NOTICE :通知错误,仅通知一下,不影响执行 ### 2.2 用户错误 表示自定义的错误、警告、通知 - E_USER_ERROR - E_USER_WARNING - E_USER_NOTICE ### 2.3 其他 - E_ALL 所有错误的集合 ### 2.4 补充 所有以E开头的错误常量,由一个字节存储,每种错误对应一个bit位,可以使用位运算进行错误控制 例如:排除通知级错误 E_ALL & ~E_NOTICE 对E_NOTICE按位取反,让他对应的位为0,然后和E_ALL按位与,  ` ## 3 错误触发 自动触发:主要针对语法错误和运行时错误,系统自动输出错误信息 人为触发:知道这个地方可能出现逻辑错误,在出错之前,用判断代码来手动触发错误提示 **trigger_error** ( string `$error_msg` [, int `$error_type` = E_USER_NOTICE ] ) : bool ```php // 题外话 设置header header('content-type:text/html;charset=utf8'); // 语法错误和运行错误会自动触发 // 如果要手动触发用户定义的错误,可以这么做 // 假设有一个除法函数,我们要对第二个参数进行检验,如果为0,就触发错误,并结束执行,默认为notice级别,可修改 function divide($a, $b) { if ($b == 0) { // trigger_error('除数不能为0', E_USER_ERROR); trigger_error('除数不能为0'); return false; } return $a / $b; } // 没报错 echo divide(1,2); // 报错 echo divide(1,0); // 由于默认是notice错误,所以不影响后面执行 echo divide(1,1); ``` ## 4 错误设置 设置是否显示错误,以及显示什么级别的错误 方式一: 打开php.ini全局配置文件,修改以下两项 display_errors: On/Off error_reporting: 错误级别 方式二: 在php脚本中,使用php的相关函数设置 error_reporting() 设置显示的错误级别 ini_set(配置项,配置值); 修改配置 exempli gratia(例如 eg) ini_set('display_errors',1); ini_set('error_reporting',E_ALL); 注意:脚本中的配置修改比配置文件级别更高 ## 5 设置错误日志 生产环境中,一般会关闭错误信息提示,但又需要记录偶尔的报错,可以到php.ini中配置错误日志功能 - 开启日志 log_errors = On - 指定日志路径 error_log = e:/php/errlog/php_errors.log ## 6 自定义错误处理 ```php <pre> 1 最简单的错误处理:trigger_error()函数,但不会阻止系统报错 2 php提供了一种用户处理错误的机制,将自定义的错误处理函数添加到系统错误处理句柄中,发生错误时回调该函数进行对应处理 set_error_handler用法: set_error_handler( callable $error_handler[, int $error_types = E_ALL | E_STRICT] ) : mixed 参数一:$error_handler 传入的回调函数有五个实参可接收 handler( int $errno, string $errstr[, string $errfile[, int $errline[, array $errcontext]]] ) : bool $errno 错误级别 是一个integer类型 必须参数 $errstr 错误信息 string类型 必须参数 $errfile 错误的文件 $errline 错误的行数 $errcontext 包含错误所处作用域内所有变量的数组array php7.2.0后被废除,不推荐使用 参数二:$error_types 指定错误类型掩码,可以屏蔽某些错误触发error_handler 如果函数返回 FALSE,标准错误处理处理程序将会继续调用。 返回true则不会继续调用标准错误处理程序。 题外话:句柄是啥? 句柄:handle,有操作控制之意,是一种中间媒介,在代码中,则是一种数字标记,通过句柄可以访问与之对应的对象,类似于指针,但是不会暴露该对象真实地址 例子:你要找李华,让他帮你买一包薯片,指针就是李华此时的所在地,句柄就是李华的手机号,李华可能在超市买东西,也可能在街上溜达,所以你很难知道他此时具体在哪,不过你可以给他打电话,通过无线电建立了一个快速通道,直接把要做的事情告诉李华。 “句柄(handle),有两种解释 第一种解释:句柄是一种特殊的智能指针 。当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄。 第二种解释:整个Windows编程的基础。 句柄是Windows用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。” https://www.php.cn/faq/418211.html https://www.zhihu.com/question/27656256 https://blog.csdn.net/qq_39618306/article/details/78996840 指针和句柄的区别:https://blog.csdn.net/yipiankongbai/article/details/17404247 句柄是指针的指针,由于所管理对象的内存地址会发生改变,为了更好管理他们,就用句柄作为中介。使用时不需要关心对象实际所在地址,只要根据句柄来找中介,通过中介访问对象。 </pre> <?php function errHandler($errno, $errstr, $errfile, $errline) { // 判断错误是否属于系统配置中所要显示的错误级别 // error_reporting()没有参数,表示获取系统错误处理对应级别 if (!(error_reporting() & $errno)) { return false; // 返回false,表示继续调用标准错误处理程序 } // 根据不同类型进行处理 switch ($errno) { case E_ERROR: case E_USER_ERROR: echo 'fatal error in file' . $errfile . 'on line' . $errline.'<br>'; echo 'error info:' . $errstr; break; case E_WARNING: case E_USER_WARNING: echo 'warning in file' . $errfile . 'on line' . $errline.'<br>'; echo 'error info:' . $errstr; break; case E_NOTICE: case E_USER_NOTICE: echo 'notice in file' . $errfile . 'on line' . $errline.'<br>'; echo 'error info:' . $errstr; break; } return true; // 返回true 表示阻止系统标准错误处理程序执行 } echo $a; // 标准的错误处理 // 将自定义错误处理函数添加到系统错误处理句柄中 set_error_handler('errHandler'); echo $a; // 自定义的错误处理 ``` # 字符串 ## 1 定义方式 ### 方式1 引号定义 用成对的单引号或双引号包裹即可 - 适合没有结构要求的字符串 - 适合不超过一行的 ### 方式2 边界符定义 - nowdoc 定义单引号字符串 - heredoc 定义双引号字符串 ```php https://www.php.cn/php-weizijiaocheng-381946.html <br> <?php // 1.引号定义 // 2.结构化定义 // 但是我用完发现好像都是有结构的。。。? $str1 = "双引号 定义"; $str2 = '单引号 定义'; // 定界符heredoc和nowdoc $str3 = <<<EOD1 heredoc: >>>后跟自定义标志符,然后回车输入字符串本身,最后回车,以自定义标志符结尾。 定义双引号字符串 变量将会解析,方法不会 如:$str1 被解析了(后面要空格)或者用花括号包起来 {$str1} EOD1; $str4 = <<<'EOD2' nowdoc: 类似heredoc,但是自定义标志符要用单引号包裹,且不会解析变量。 定义单引号字符串 $str1没有解析 EOD2; echo $str1.'<br>'. $str2.'<br>'. $str3.'<br>'. $str4; ``` ## 2 字符串转义 特定字符需要通过反斜杠+字母来表示 \\' 在单引号字符串中显示单引号 \\" 在双引号字符串中显示双引号 \r 本意是回到行首位置,现在一般代表回车 \n 新的一行 \t tab 或者多个空格 \\$ 由于$符表示变量,加\\转义显示$ ```php <?php // 单引号字符串只转义单引号 $a = '\'\"\r\n\t\$'; $b = "\'\"\r\n\t\$"; echo $a . '<br>'; // 显示 '\"\r\n\t\$ 可以看到只转义了单引号 echo $b . '<br>'; // 显示 \'" $ 可以看到,除了单引号没转义,其他都转义了 // 由于双引号字符串识别$,所以可以解析变量 // 由于直接写需要有空格,导致输出也有空格,可以用{}包裹起来 $c = "$a 被解析了 {$b}也被解析了"; echo $c; ``` ## 3 字符串长度 通过strlen()可以得到字符串所占字节长度,但是中文不止1字节。 由于文件编码方式不同,中文可能占2字节(如bgk),也可能占3字节(如uft8) 为了解决多字节字符串长度问题,需要加载mbstring扩展(multi bytes string意为多字节字符串) 进入php.ini文件,去掉这行前面的分号 `extension=mbstring` 开启后,可以使用一些mb_开头的扩展函数 如mb_strlen: ``` mb_strlen( string $str [, string $encoding = mb_internal_encoding()] ) : mixed ``` - 参数1:要统计的字符串 - 参数2:按照指定字符集统计(默认为内部字符编码)
本作品采用
《CC 协议》
,转载必须注明作者和本文链接