🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# :-: 一、传统的错误处理方式 ```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(); ```