PHP程序员PHP经验分享

Modern PHP 笔记(二):良好实践

2017-12-01  本文已影响207人  郝开心信札

系列笔记:
Modern PHP 笔记(一):语言特性
Modern PHP 笔记(二):良好实践
Modern PHP 笔记(三):部署测试和调优

相比于上一篇笔记Modern PHP 笔记(一):语言特性,第二部分侧重讲标准和良好实践,更加实战。

第三章:标准

PHP-FIG(PHP Framework Interop Group)2009年

框架的互操作性

通过接口、自动加载、代码风格,使框架相互合作

PSR标准

PSR: PHP Standard Recommendation(PHP推荐标准)

可以看点击链接看详细的中文版。很多方案在起草中,也有废弃的,比如PSR-4就是替代PSR-0的

第四章:组件

多用组件,从框架的封闭生态中走出来,减少重复造轮子。

组件是什么?

打包的代码,一系列相关的类、接口、性状

组件与框架对比

框架(尤其是较旧的框架)的问题是:需要更多投入,框架提供很多工具,但是可能缺少我们需要的。
把第三方代码集成上去费时费力。框架本身的维护也需要很多人力。

使用正确的工具做正确的事

查找组件

组件库Packagist https://packagist.org/

优秀组件可参考Awesome PHP:https://github.com/ziadoz/awesome-php

使用组件

使用composer下载并自动加载依赖组件

使用composer

composer require vendor/package

composer.lock文件会列出使用的所有组件和具体版本号,确保组件版本一致。

composer install // 不会更新.lock
composer update  // 更新.lock到最新版

自动加载

只需要一句,不用一一引入

require 'vendor/autoload.php'

composer和私有仓库

不方便开源的组件也可以使用composer

创建PHP组件

  1. 取一个厂商名和包名

  2. 定一个命名空间

  3. 文件系统

     src/    源码
     tests/     测试
     composer.json   composer的配置文件,描述组件、依赖等
     README.md
     CONTRIBUTING.md   说明如何为这个组件做贡献
     LISENSE      组件许可证
     CHANGELOG.md   每个版本引入的改动
    
  4. composer.json

     require 列出需要的最小依赖
     require-dev 列出开发组件需要的依赖
    
  5. 实现组件

  6. 发到版本控制

  7. 提交到 Packagist

  8. 使用组件 composer require

第五章:良好实践

过滤、验证和转义

不要相信任何人。

包括:

过滤输入

转义或删除不安全的字符。

HTML

使用htmlentities()函数,但是它默认不会转义单引号,正确使用方式:第一个参数是输入字符串,
第二额参数设为ENT_QUOTES常量,转义单引号,第三个参数设为输入字符串的字符集。

$htmlentities($input, ENT_QUOTES, 'UTF-8');

如果需要更多过滤HTML方式,可以使用HTML Purifier库。

SQL查询

使用PDO预处理语句

用户资料信息

filter_var()filter_input()函数

验证数据

区别于过滤数据会删除,验证不会,只是确保符合特定格式。
传递FILTER_VALIDATE_*标志给filter_var()函数。验证失败返回false,否则返回原值。

    //验证电子邮件
    $input = 'john@example.com'
    $isEmail = filter_var($input, FILTER_VALIDATE_EMAIL);
    if ($isEmail !== false) {
        echo 'success';
    } else {
        echo "fail";
    }

推荐组件:

转义输出

很多模板引擎(e.g., twig、smarty)会自动转义,否则使用htmlentities($output, ENT_QUOTES, 'UTF-8');

密码

使用bcrypt计算用户密码的哈希值

应该用哈希,而不是加密。加密是双向算法,可以解密,而哈希是单向算法。
哈希算法很多,一般用bcrypt,与MD5和SHA1不同,bcrypt故意设计的很慢,多次处理数据(工作因子)。

密码哈希API

注册用户

     // 验证电子邮件
     // 验证密码
     // 创建密码哈希值
     // 创建用户账户
     // 重定向登录账户

登录用户

     // 从请求主体获取电子邮件地址
     // 从请求主体获取密码
     // 使用电子邮件查询账户

     password_verify();
     // 验证密码和账户哈希值是否匹配

     password_needs_rehash();
     // 如果需要,重新计算哈希值(最新的算法)
     // 把登录状态保存在会话中
     // 重定向到个人资料页

PHP5.5.0之前,使用组件ircmaxell/password-compat

日期、时间和时区

设置默认时区

// php.ini
date.timezone = 'America/New_York';

// *.php
date_default_timezone_set('America/New_York');

DateTime类

构造$datetime = new DateTime('2014-09-08 5:03 AM');
自定义格式DateTime::createFromFormat('M j, Y H:i:s', 'Jan 2, 2014 23:09:12')

DateInterval类

表示固定的时间段,DateInterval用于修改DateTime实例.

    $datetime = new DateTime('2014-09-08 5:03 AM');
    $interval = new DateInterval('P2W');
    $datetime->add($interval);
    echo $datetime->format('Y-m-d H:i:s');

DateTimeZone类

    $timezone = new DateTimeZone('America/New_York');
    $datetime = new DateTime('2014-09-08 5:03 AM', $timezone);

DatePeriod类

一段时期内反复出现的一系列日期和时间

    $period = new DatePeriod($startDateTime, $interval, 3);

nesbot/carbon组件

数据库

PDO扩展,PHP Data Objects,PHP数据对象,是一系列类,抽象了不同数据库的具体实现。

这里实际上现在框架的ORM用的很好,不需要直接PDO了。

    // 预处理语句
    $sql = 'select id from user where email = :email';
    $statement = $pdo->prepare($sql);

    $email = filter_input(INPUT_GET, 'email');
    $statement->bindValue(':email', $email);
    // ':email'是占位符

    // 查询结果
    $statement->execute();

    // 迭代结果
    while (($result = $statement->fetch(PDO::FETCH_ASSOC)) !== false) {
        echo $result['email'];
    }

事务

    $pdo->beginTransaction();
    // sql
    $pdo->commit();

多字节字符串

使用mbstring扩展,比如用mb_strlen()代替原生的strlen()

处理字符编码:

流的作用是在出发地和目的地之间传输数据。出发地和目的地可以是文件、命令行进程、网络连接、
ZIP或TAR压缩文件、临时内存、标准输入和输出、或者是PHP流封装协议实现的其他资源。就是管道

流封装协议

流协议和目标格式:

    <scheme>://<target>

下面例子里file_get_contents()的字符串参数是流标识符,只是因为HTTP流协议就是这样,像URL

    $json = file_get_contents(
        'http://api.flickr.com....'
    )

还有其他file://流封装协议、php://流封装协议

流上下文

有些流接受的可选参数,成为流上下文
使用stream_context_creat()函数创建

流过滤器

流真正的强大之处:过滤、转换、添加、删除流中传输的数据。
string.toupper等,大多需要自定义stream_filter_append()

自定义流过滤器

自定义流过滤器是个PHP类,扩展内置的php_user_filter类,实现一些方法,然后用
stream_filter_register()注册。

错误和异常

错误会导致脚本停止,异常时PHP错误处理面向对象的产物,异常要先实例化,然后抛出,最后再捕获。

异常

异常是Exception类的对象。
$exception = new Exception('msg', -1);
抛出异常throw new Exception('msg', -1);,异常抛出后程序会终止。
捕获异常try {...} catch { }

异常处理程序

设置一个全局异常处理程序,捕获所有未捕获的异常。

    set_exception_handler(function (Exception $e) {
        // 处理并记录异常
    });

    // 编写其他代码

    // 还原之前的异常处理程序
    restore_exception_handler();

错误

在开发环境,显示并记录所有错误信息;

在生产环境,记录大多数错误信息,但不显示出来;

    set_error_handler();  // 全局错误处理程序
    restore_error_handler();

在开发环境中处理错误和异常

使用Whoops组件

在生产环境处理错误和异常

使用Monolog组件

上一篇 下一篇

猜你喜欢

热点阅读