# :-: 一、传统的错误处理方式
```php
namespace jiangshi\ouyangke;
// 传统方式的错误处理
class Calculator{
protected $defaultOperators = ['+', '-', '*', '/', '%'];
protected $result;
public function __construct(...$operators){
// 判断操作是否在有效范围内
foreach ($operators as $operator) {
if (in_array($operator, $this->defaultOperators)) {
continue;
} else {
die('操作符错误');
}
}
// 更新操作符类型
$this->defaultOperators = $operators;
}
// 运算方法
public function operation($type,...$args){
// 判断操作符合法性
if (in_array($type, $this->defaultOperators)) {
$num = count($args);
switch ($num) {
case 0:
die('参数不能为空');
break;
case ($num < 2):
die('参数不能少于2个');
break;
default:
// 用参数数组的第一个值初始化$this->result属性,该属性保存着返回值
// 同时, $this->>result 也做为所有运算的第一个操作数
$this->result = array_shift($args);
if (is_numeric($this->result)) {
$this->execute($type, ...$args);
} else {
die('第一个参数必须数值型');
}
}
} else {
die('操作类型错误');
}
// 运算结果四舍五入(保留小数点后2位)
return round($this->result, 2);
}
// 运算执行器方法
protected function execute($type, ...$args){
foreach ($args as $arg) {
// 判断当前操作数是否数字/可转为数字的字符串
if (is_numeric($arg)) {
switch ($type) {
case '+': // 加法
$this->result += $arg;
break;
case '-': // 减法
$this->result -= $arg;
break;
case '*': // 乘法
$this->result *= $arg;
break;
case '/': // 除法
if ($arg !== 0) {
$this->result /= $arg;
break;
} else {
die('除数不能为0');
}
case '%': // 取模
$this->result %= $arg;
break;
}
} else {
die('操作数类型错误');
}
}
}
}
// 实例化, 并自定义允许进行的操作类型
//$calculator = new Calculator('+','-','*','/');
//$calculator = new Calculator('+','-','*','888');
$calculator = new Calculator('+','-');
echo '<per>';
//echo $calculator->operation('+'); // 参数不能为空
//echo $calculator->operation('+', 100); // 参数不能少于2个
//echo $calculator->operation('+', 'abc',888); // 第一个参数必须是可计算的数值或数值型字符串
echo $calculator->operation('+', '100',888); // 988
echo '<hr>';
echo $calculator->operation('-', '100',888); // -788
echo '<hr>';
// 添加运算符: 乘法与除法
$calculator = new Calculator('+','-','*', '/');
echo $calculator->operation('*', '100',888); // 88800
echo '<hr>';
echo $calculator->operation('/', '100',888); // 0.11
```
*****
# :-: 二、系统异常类常规处理
* Exception 类是可以进行扩展的
* Exception 中只有__construct()和__toString()允许扩展,其它都是最终方法final,不允许扩展
```php
// 异常类: Exception
namespace jiangshi\ouyangke;
use Exception;
// 用户代码应该全部放在try 块中
try {
class Calculator{
protected $defaultOperators = ['+', '-', '*', '/', '%'];
protected $result;
public function __construct(...$operators){
// 判断操作是否在有效范围内
foreach ($operators as $operator) {
if (in_array($operator, $this->defaultOperators)) {
continue;
} else {
// die('操作符错误');
throw new Exception('操作符错误', 101);
}
}
// 更新操作符类型
$this->defaultOperators = $operators;
}
// 运算方法
public function operation($type,...$args){
// 判断操作符合法性
if (in_array($type, $this->defaultOperators)) {
$num = count($args);
switch ($num) {
case 0:
throw new Exception('参数不能为空', 102);
// die('参数不能为空');
break;
case ($num < 2):
// die('参数不能少于2个');
throw new Exception('参数不能少于2个', 103);
break;
default:
// 用参数数组的第一个值初始化$this->result属性,该属性保存着返回值
// 同时, $this->>result 也做为所有运算的第一个操作数
$this->result = array_shift($args);
if (is_numeric($this->result)) {
$this->execute($type, ...$args);
} else {
// die('第一个参数必须数值型');
throw new Exception('第一个参数必须数值型', 104);
}
}
} else {
// die('操作类型错误');
throw new Exception('操作类型错误', 105);
}
// 运算结果四舍五入(保留小数点后2位)
return round($this->result, 2);
}
// 运算执行器方法
protected function execute($type, ...$args){
foreach ($args as $arg) {
// 判断当前操作数是否数字/可转为数字的字符串
if (is_numeric($arg)) {
switch ($type) {
case '+': // 加法
$this->result += $arg;
break;
case '-': // 减法
$this->result -= $arg;
break;
case '*': // 乘法
$this->result *= $arg;
break;
case '/': // 除法
if ($arg !== 0) {
$this->result /= $arg;
break;
} else {
// die('除数不能为0');
throw new Exception('除数不能为0', 106);
}
case '%': // 取模
$this->result %= $arg;
break;
}
} else {
// die('操作数类型错误');
throw new Exception('操作数类型错误', 107);
}
}
}
}
// 实例化, 并自定义允许进行的操作类型
$calculator = new Calculator('+','-','*', '/');
echo '<per>';
// echo $calculator->operation('*');
// echo $calculator->operation('*',30);
// echo $calculator->operation('*','abc',999);
echo $calculator->operation('*','379',200);
echo '<hr>';
echo $calculator->operation('/', 678,234);
} catch (Exception $e) {
// 使用异常,将执行过程中可能出现的错误进行统一管理,更加优雅高效
// getCode(): 获取自定义错误代码, getMessage(): 获取自定义错误信息
echo $e->getCode(). ': ' .$e->getMessage();
}
```
*****
# :-: 三、自定义异常类处理
* 下面我们来创建一个自己的异常类, 专用于处理算术运算中可能出现的错误
* 基本要求是: 错误代码加粗, 提示文本描红, 并要求换行显示
```php
// 异常类: Exception
namespace jiangshi\ouyangke;
use Exception;
// 自定义异常类
class CalException extends Exception{
public function __construct($message = "", $code = 0){
parent::__construct($message, $code);
}
public function errorInfo(){
return
<<< ERROR
<h2>
<strong>{$this->getCode()}: </strong>
<span style="color: red">{$this->getMessage()}</span>
</h2>
ERROR;
}
}
// 以try 块中,所有的 Exception 类全部替换成 CalException 类即可
try {
class Calculator{
protected $defaultOperators = ['+', '-', '*', '/', '%'];
protected $result;
public function __construct(...$operators){
// 判断操作是否在有效范围内
foreach ($operators as $operator) {
if (in_array($operator, $this->defaultOperators)) {
continue;
} else {
// die('操作符错误');
throw new CalException('操作符错误', 101);
}
}
// 更新操作符类型
$this->defaultOperators = $operators;
}
// 运算方法
public function operation($type,...$args){
// 判断操作符合法性
if (in_array($type, $this->defaultOperators)) {
$num = count($args);
switch ($num) {
case 0:
throw new CalException('参数不能为空', 102);
// die('参数不能为空');
break;
case ($num < 2):
// die('参数不能少于2个');
throw new Exception('参数不能少于2个', 103);
break;
default:
// 用参数数组的第一个值初始化$this->result属性,该属性保存着返回值
// 同时, $this->>result 也做为所有运算的第一个操作数
$this->result = array_shift($args);
if (is_numeric($this->result)) {
$this->execute($type, ...$args);
} else {
// die('第一个参数必须数值型');
throw new CalException('第一个参数必须数值型', 104);
}
}
} else {
// die('操作类型错误');
throw new CalException('操作类型错误', 105);
}
// 运算结果四舍五入(保留小数点后2位)
return round($this->result, 2);
}
// 运算执行器方法
protected function execute($type, ...$args){
foreach ($args as $arg) {
// 判断当前操作数是否数字/可转为数字的字符串
if (is_numeric($arg)) {
switch ($type) {
case '+': // 加法
$this->result += $arg;
break;
case '-': // 减法
$this->result -= $arg;
break;
case '*': // 乘法
$this->result *= $arg;
break;
case '/': // 除法
if ($arg !== 0) {
$this->result /= $arg;
break;
} else {
// die('除数不能为0');
throw new CalException('除数不能为0', 106);
}
case '%': // 取模
$this->result %= $arg;
break;
}
} else {
// die('操作数类型错误');
throw new CalException('操作数类型错误', 107);
}
}
}
}
// 实例化, 并自定义允许进行的操作类型
$calculator = new Calculator('+','-','*', '/');
echo '<per>';
// echo $calculator->operation('*');
// echo $calculator->operation('*',30);
// echo $calculator->operation('*','abc',999);
// echo '<hr>';
echo $calculator->operation('*','379',200);
echo '<hr>';
echo $calculator->operation('/', 678,234);
} catch (CalException $e) {
// 使用异常,将执行过程中可能出现的错误进行统一管理,更加优雅高效
// getCode(): 获取自定义错误代码, getMessage(): 获取自定义错误信息
// echo $e->getCode(). ': ' .$e->getMessage();
echo $e->errorInfo();
}
```
*****
# :-: 四、框架中的模型的实现原理
* 框架中的模型, 通常会与一张数据表对应, 而模型对象,则与数据表中的一条记录对应
* 这种数据表到类的映射关系, 对于面向对象的方式管理数据库极其重要
```php
namespace jiangshi\ouyangke;
use PDO;
class User{
private $uid;
private $phone;
private $name;
private $age;
private $sex;
private $last_time;
// 属性重载
public function __get($name){
return $this->$name;
}
public function __set($name, $value){
$this->$name = $value;
}
// 构造方法: 用于初始化或设置默认值
public function __construct(){
// 设置属性值的自动转换
// 将时间戳转为日期字符串
$this->last_time = date('Y/m/d', $this->last_time);
// 将性别转为可识别的字符
$this->sex = $this->sex ? '男' : '女';
}
}
$pdo = new PDO('mysql:host=localhost;dbname=ouyangke','root','root');
$stmt = $pdo->prepare('SELECT * FROM `user`');
$stmt->setFetchMode(PDO::FETCH_CLASS,User::class);
$stmt->execute();
//$obj = $stmt->fetch();
// 返回的每一条记录都是User类的实例对象
//var_dump($obj);
while ($user = $stmt->fetch()) {
// 测试
// echo '<pre>' . print_r($user, true);
// 属性重载的应用
echo "<li>{$user->uid}: {$user->name}--{$user->sex}--{$user->phone}--{$user->last_time}</li>";
}
```
*****
# :-: 五、文件上传的完整流程
>[info] index.html文件
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--请求类型必须是POST, 数据编码类型必须是: 复合表单数据,让服务器知道上传的是文件-->
<form action="demo5.php" method="post" enctype="multipart/form-data">
<input type="file" name="my_file" id="">
<!--隐藏域:限制上传文件大小, 不超过php.ini: upload_max_filesize值-->
<!--1M=1024k=1048576字节, 3M = 3145728字节-->
<input type="hidden" name="MAX_FILE_SIZE" value="3145728">
<button>上传</button>
</form>
</body>
</html>
```
>[info] upload.php文件
* 前单表单中进行一些必要的设置, 以支持文件上传
* 后端PHP主要使用超全局变量: $_FILES 来处理上传的文件
```php
// 1. 配置上传参数
// 设置允许上传的文件类型
$fileType = ['jpg', 'jpeg', 'png', 'gif'];
// 设置允许上传的最大文件长度
$fileSize = 3145728;
// 上传到服务器上指定的目录
$filePath = '/uploads/';
// 上传的原始文件名
$fileName = $_FILES['my_file']['name'];
// 上传保存在服务器上的临时文件名
$tempFile = $_FILES['my_file']['tmp_name'];
// 2. 判断上传是否成功?
// 主要是通过$_FILES['my_file']['error']值, 等于0成或,大于1出错,出错类型用switch分析
$uploadError = $_FILES['my_file']['error'];
if ($uploadError > 0) {
switch ($uploadError) {
case 1:
case 2: die('上传文件不允许超过3M');
case 3: die('上传文件不完整');
case 4: die('没有文件被上传');
default: die('未知错误');
}
}
// 3. 判断文件扩展名是否正确?
$extension = explode('.',$fileName)[1];
if (!in_array($extension, $fileType)) {
die('不允许上传' . $extension . '文件类型');
}
// 4. 为了防止同名文件相互覆盖, 应该将上传到指定目录的文件重命名,例如用md5+时间戳
$fileName = date('YmdHis',time()).md5(mt_rand(1,99)) . '.' . $extension;
// 5. 判断文件是否上传成功?
// 判断是否是通过post上传的
if (is_uploaded_file($tempFile)) {
if (move_uploaded_file($tempFile, __DIR__ . $filePath.$fileName)) {
// 提示用户上成功,并返回上一个页面,再强行刷新当前页面
echo '<script>alert("上传成功");history.back();</script>';
} else {
die('文件无法移动到指定目录,请检查目录权限');
}
} else {
die('非法操作');
}
exit();
```
- 序言
- PHP基础
- 认识PHP
- 环境安装
- PHP语法
- 流程控制
- PHP数组
- PHP函数
- PHP类与对象
- PHP命名空间
- PHP7新特性
- PHP方法库
- PHP交互
- 前后端交互
- 项目常规开发流程
- MySQL数据库
- 会话控制
- Ajax分页技术
- 细说函数
- 类与对象
- 对象进阶
- 类与对象进阶
- OOP面向对象
- 设计模式
- 路由与模板引擎
- 异常类
- PHP爬虫
- PHP抓取函数
- PHP匹配函数
- 正则表达式
- PHP字符串函数
- 抓取实战
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安装
- 架构
- 数据库
- 数据库操作
- 视图
- 模版
- 模型
- 杂项
- 命令行
- 交互
- 微信小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- 百度小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- Linux
- 服务器上线流程
- 安装svn
- MySQL
- 认识MySQL
- MySQL函数
- 杂项
- composer依赖管理工具