PHP开发要点与技巧总结(二)

  1. 1 == 'a'、0 == 'a'、97 == '97a'?这里边牵涉到的是默认数据类型转换。
    // 无输出
    if ('0') {
        echo "'0' is true\n";
    }
    
    //'a' is true
    if ('a') {
        echo "'a' is true\n";
    }
    
    // 无输出
    if (1 == 'a') {
        echo "1 == 'a' is true\n";
    }
    
    //0 == 'a' is true
    if (0 == 'a') {
        echo "0 == 'a' is true\n";
    }
    
    //97 == '97a' is true
    if (97 == '97a') {
        echo "97 == '97a' is true\n";
    }
  2. 多次 ++ 与 -- 
    $n = 5;
    echo $n++ * $n--;//30
  3. count / strlen / mb_strlen :count用于统计数组元素或对象属性个数,但不能用于字串长度统计(否则总是返回1);strlen用于获取字符串字节长度,而非字符数;mb_strlen获取多字节编码字符串的长度。
  4. mysqlnd:当使用mysqlnd而非libmysqlclient作为MySQL客户端库时,buffered queries是默认模式;故要使用unbuffered queries模式,无论使用mysqli、pdo_mysql、mysql三种中的任何一种API都要手动开启,特别是做大数据集查询的时候。
    $pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_pass');
    $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
    
    $uresult = $pdo->query("SELECT Name FROM City");
    if ($uresult) {
       while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) {
           echo $row['Name'] . PHP_EOL;
       }
    }
  5. Zend Guard:用于对PHP代码加密与混淆,服务端需要安装Zend Guard Loader库来解密。在Ubuntu 64位系统上还需要安装 lib32z1、libglu1-mesa两个库

    sudo apt-get install lib32z1 libglu1-mesa:i386
  6. OpenSSL对称加密: openssl 1.0.1版本后,运行时期自动检测是否支持 AES-NI (Advanced Encryption Standard New Instructions,基本上2010年之后的Intel CPU都支持,另外AMD和ARM的一些型号也支持)。查看处理器是否支持 AES-NI 执行 cat /proc/cpuinfo | grep aes | wc -l

    1) OpenSSL采用PKCS7 CBC填充,而mcrypt无填充。
    2)OpenSSL AES-256相当于MCRYPT_RIJNDAEL_128(32位key),但mcrypt已被废弃。
    3)先加密,后认证(Message Authenticity,HMAC),防止被篡改的消息仍然被解密。
    4)AES-128、AES-192、AES-256密钥长度分别是128、192、256位,AES-128和AES-256加密处理轮数分别是10、14轮。
    5)AES基于数据块(16字节,不足则填充)加密,包括ECB(Electronic Code Book,电子密码本)、CBC(Cipher Block Chaining,加密块链)、CFB(Cipher FeedBack,加密反馈)、OFB(Output FeedBack,输出反馈)、CTR(Counter,计数)五种加密模式。
    6)在OpenSSL模块中有三种资源类型:第一种是一个 pkey(公钥或私钥)标识符,第二种是一个X509证书标识符,第三种是 CSR (证书签名请求) 标识符。OPENSSL_ZERO_PADDING、OPENSSL_NO_PADDING选项不能用于CBC、CTR。
    7)AES-256-CBC vs AES-256-CTR:CTR加解密均可并行,CBC解密可并行;CTR能避免Padding Oracle Attacks。
    8)OpenSSL与JAVA AES/ECB/PKCS5Padding问题:https://blog.csdn.net/kikajack/article/details/79273612
    9)Java AES/ECB/PCKS5Padding:
    <?php
    
    class Aes
    {
        public $method = 'AES-128-ECB';
        private $key;
    
        public function __construct($key)
        {
            $this->key = substr(openssl_digest(openssl_digest($key, 'sha1', true), 'sha1', true), 0, 16);
        }
    
        /**
         * 密文解密
         * @return string
         */
        public function decrypt($content)
        {
            return $this->_pkcs5Unpad(openssl_decrypt($content, $this->method, $this->key, OPENSSL_ZERO_PADDING), 16);
        }
    
        /**
         *
         */
        public function encrypt($content)
        {
            $content = $this->_pkcs5Pad($content, 16);
            return openssl_encrypt($content, $this->method, $this->key, OPENSSL_ZERO_PADDING);
    
        }
    
        //PKCS5Padding 补码方式
        private function _pkcs5Pad($text, $blockSize)
        {
            $pad = $blockSize - (strlen($text) % $blockSize);
            return $text . str_repeat(chr($pad), $pad);
        }
    
        private function _pkcs5Unpad($text)
        {
            $end = substr($text, -1);
            $last = ord($end);
            $len = strlen($text) - $last;
            if (substr($text, $len) == str_repeat($end, $last)) {
                return substr($text, 0, $len);
            }
            return false;
        }
    }
  7. parse_url():解析 URL,返回其组成部分
    $url = 'http://username:password@hostname/path?arg=value#anchor';
    
    print_r(parse_url($url));
    
    echo parse_url($url, PHP_URL_PATH);
    
    //Array
    (
        [scheme] => http
        [host] => hostname
        [user] => username
        [pass] => password
        [path] => /path
        [query] => arg=value
        [fragment] => anchor
    )
    /path
  8. parse_str() 与http_build_query():parse_str()将字符串解析成多个变量,http_build_query()生成 URL-encode 之后的请求字符串。
    // http_build_query
    //0=foo&1=bar&2=baz&3=boom&cow=milk&php=hypertext+processor
    //myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk&php=hypertext+processor
    $data = array('foo', 'bar', 'baz', 'boom', 'cow' => 'milk', 'php' =>'hypertext processor');
    echo http_build_query($data) . "\n";
    echo http_build_query($data, 'myvar_');
    
    
    // parse_str
    $str = "first=value&arr[]=foo+bar&arr[]=baz";
    parse_str($str, $output);
    echo $output['first'];  // value
    echo $output['arr'][0]; // foo bar
    echo $output['arr'][1]; // baz
  9. curl
    // 包含响应头信息
    curl_setopt($ch, CURLOPT_HEADER, 1);
    // 将只获取响应头
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    // 重定向是有条件的: ini_get('open_basedir') == '' && ini_get('safe_mode') == false.
    // CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set...
    // 参考 https://blog.eexit.net/curl-forward-post-over-http-redirections/ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    // 请求方法
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    // 限制最大重定向次数 curl_setopt($ch, CURLOPT_MAXREDIRS, 5); // 返回响应内容而不是直接输出到页面 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // $post为数组时,最好用http_build_query($post)将其转为字符串 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));

     

  10. 外部接口编码转换:如从当前编码UTF-8转换为GBK
    header("Content-Type: text/html; charset=GBK");
    echo mb_convert_encoding($html, 'GBK', 'UTF-8');
  11. SoapClient::__soapCall 与 SoapClient::__call:__soapCall参数传递方式四值得注意
    $client = new SoapClient("some.wsdl");
    $params = array('username'=>'name', 'password'=>'secret');
    
    // 方式一:
    $client->SomeFunction($a, $b, $c);
    
    // 方式二:
    $client->__soapCall("SomeFunction", array($a, $b, $c));
    
    // 方式三:
    $client->login($params);
    
    // 方式四:
    $client->__soapCall('login', array($params));
    
    // 方式五:
    call_user_func_array(array($client, 'login'), [$params]);
  12. 时间比较

    $holder_birthday = date_create('1984-04-28');
    
    // 方式一:
    $diff = date_diff($holder_birthday, date_create());
    
    // 方式二:
    $diff = $holder_birthday->diff(date_create());
    
    if ($diff->invert || $diff->y < 18) {
        $this->errcodeSet('投保人年龄必须大于18周岁!');
        return false;
    }
  13. 动态访问对象属性

    $key = 'name';
    
    echo $obj->{$key.'Pro'};
  14. 转义字符:转义字符不能以单引号引出,必须以双引号引出。

    $this->conf = str_replace("\r\n","\n", $this->conf);
  15. 后期静态绑定

    class A
    {
        function __construct()
        {
            echo self::class . "\n";
            echo static::class . "\n";
        }
    }
    
    class B extends A
    {
    
    }
    
    // A
    // B
    $s = new B();
  16. 链式包含(include/include_once/require/require_once):链尾到链首的全局作用域是等效的。

    1. 当一个文件被包含时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。
    
    2. 如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的。
  17. fwrite/fputs: 当 $fwrite=0 时,下列代码可能导致死循环。参考http://php.net/manual/vote-note.php?id=96951&page=function.fwrite&vote=up

    // BROKEN function - infinite loop when fwrite() returns 0s 
    function fwrite_stream($fp, $string) { 
        for ($written = 0; $written < strlen($string); $written += $fwrite) { 
            $fwrite = fwrite($fp, substr($string, $written)); 
            if ($fwrite === false) { 
                return $written; 
            } 
        } 
        return $written; 
    } 
  18. Windows PHP版本选择TS & NTS 
  19. string字串操作:一个由字节组成的数组再加上一个整数指明缓冲区长度。并无如何将字节转换成字符的信息,由程序员来决定。字符串由什么值来组成并无限制;特别的,其值为 0(“NUL bytes”)的字节可以处于字符串任何位置(不过有几个函数,在本手册中被称为非“二进制安全”的,也许会把 NUL 字节之后的数据全都忽略)。
    $a = 'fsafsfsfsfsff';
    // sa
    var_dump($a[1] . ${2});
  20. PHP 函数/语法结构与命名空间
    (1)在一个命名空间中,当 PHP 遇到一个非限定的类、函数或常量名称时,它使用不同的优先策略来解析该名称。类名称总是解析到当前命名空间中的名称。因此在访问系统内部或不包含在命名空间中的类名称时,必须使用完全限定名称。
    
    (2)对于函数和常量来说,如果当前命名空间中不存在该函数或常量,PHP 会退而使用全局空间中的函数或常量。
    
    (3)在用户自定义命名空间中,PHP内核函数可以被重新定义,但语言结构却不行。
  21. namespace 和 use:use常量和函数。命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字。
    <?php
    namespace test;
    define('MESSAGE', 'Hello world!');
    ?>
    namespace Name\Space {  
        const FOO = 42;  
        function f() { echo __FUNCTION__."\n"; }  
    }  
    namespace Xx {  
        use const Name\Space\FOO;  
        use function Name\Space\f;  
    
        echo FOO."\n";  
        f();  
    } 
  22. 大型整数:Large integers must be specified as strings - otherwise, PHP will coerce them to floats, resulting in a loss of precision.
  23. 高精度计算:BC Math & GMP
    // JS: 0.0006 * 100000 = 59.99999999999999
    
    // php: 100000000 * 0.0006 = 59999.99999999999
    
    // php:bcmul(100000000, 0.0006, 0) = 60;

     

  24. HEIF / ImageMagick安装
    #安装依赖包(库),不同平台包(库)名可能不同。如果以安装可免,通过yum list installed查看。 
    yum -y install gcc-c++ libtool pkg-config libjpeg-devel libpng-devel

    #安装libde265(HEVC Decoder / h.265),没有安装libx265(libheif的HEVC Encoder)
    wget https://github.com/strukturag/libde265/archive/frame-parallel.tar.gz
    tar zxvf frame-parallel.tar.gz
    cd libde265-frame-parallel
    ./autogen.sh
    ./configure
    make
    make install
    #sudo ldconfig /usr/local/lib
    #make uninstall & make distclean

    #安装libheif
    wget https://github.com/strukturag/libheif/archive/master.tar.gz
    tar zxvf master.tar.gz
    cd libheif-master
    ./autogen.sh
    #下边这条命令也可以换成 ./configure libde265_CFLAGS='-I/usr/local/include' libde265_LIBS='-lde265'
    #libde265.pc 所在的目录

    ./configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

    make
    make install
    #可能需要加载动态库配置/etc/ld.so.conf
    #sudo ldconfig /usr/local/lib
    #heif-convert能把heic转换成png、jpg
    #/usr/local/bin/heif-convert 1.heic 1.jpeg 将报 “Unknown file type in 1.jpeg”错误
    #/usr/local/bin/heif-convert 1.heic 1.jpg
    #安装imagemagick
    wget http://imagemagick.org/download/ImageMagick.tar.gz
    tar xvzf ImageMagick.tar.gz
    cd ImageMagick-7.0.8
    #环境变量(env可查看所有,export/export -n可设置/删除指定环境变量)PKG_CONFIG_PATH的值为libheif.pc所在的目录。如果configure执行发生错误,请查看config.log
    ./configure --disable-openmp PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
    make
    make install
    #sudo ldconfig /usr/local/lib
    #which identify
    #/usr/local/bin/identify /var/www/public/1.heic

    #安装PHP imagick扩展 pecl
    install imagick #php.ini启用扩展 extension=imagick.so

    #PHP-FPM reload #systemctl restart php-fpm
    #卸载 #pecl uninstall imagick
    $img = new Imagick();
    $img->readImage(__DIR__ .'/1.heic');
    //$img->resizeImage(320,240,Imagick::FILTER_LANCZOS,1);
    $img->writeImage(__DIR__ . '/1.jpg');
    $img->clear();
  25. isset():检测变量是否已设置并且非 NULL。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。同时要注意的是 null 字符("\0")并不等同于 PHP 的 NULL 常量。 如果一次传入多个参数,那么 isset() 只有在全部参数都以被设置时返回 TRUE 计算过程从左至右,中途遇到没有设置的变量时就会立即停止。

     

  26. self类:
    <?php
    class A
    {
        public $a = NULL;
    
        public function __construct($s)
        {
            $this->a = $s;
        }
    
        public function make($s)
        {
            return new self($s);
        }
    
        public function dump($obj)
        {
            if ($obj instanceof self) {
                var_dump($this, $obj);
            }
        }
    }
    
    $obj = new A('Obj-1');
    $obj->dump($obj->make('Obj-2'));
    /public/index.php:19:
    object(A)[1]
      public 'a' => string 'Obj-1' (length=5)
    /public/index.php:19:
    object(A)[2]
      public 'a' => string 'Obj-2' (length=5)
  27. private属性不可见问题:
    abstract class RuleAbstraction
    {
        // 匹配模式
        private $pattern = null;
        // 校验对象
        private $subject = null;
    
        public function setSubject($subject) {
            $this->subject = $subject;
        }
    }
    class Email extends RuleAbstraction
    {
        // E-mail正则匹配模式
        private $pattern = '/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/';
    
        /**
         * 校验EMail地址
         *
         * @return false|int
         */
        public function check()
        {
    var_dump($this);
    return preg_match($this->pattern, $this->subject); } }
    $obj = new Email();
    $obj->setSubject('shuznhi.chen@anlaa.com');
    $obj->check();//0

    var_dump:

    object(RuleEngine\Rules\Email)#9 (3) {
      ["pattern":"RuleEngine\Rules\Email":private]=>
      string(69) "/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/"
      ["subject":"RuleEngine\Rules\RuleAbstraction":private]=>
      string(22) "w12.a/qe_@124afasf.com"
      ["pattern":"RuleEngine\Rules\RuleAbstraction":private]=>
      NULL
    }
    object(RuleEngine\Rules\Email)#14 (3) {
      ["pattern":"RuleEngine\Rules\Email":private]=>
      string(69) "/^(?!_|-)(?>[\w\.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/"
      ["subject":"RuleEngine\Rules\RuleAbstraction":private]=>
      string(22) "shunzhi.chen@anlaa.com"
      ["pattern":"RuleEngine\Rules\RuleAbstraction":private]=>
      NULL
    }
  28. fmod():回被除数(x)除以除数(y)所得的浮点数余数。
    $x = 5.7;
    $y = 1.3;
    $r = fmod($x, $y);
    // $r equals 0.5, because 4 * 1.3 + 0.5 = 5.7
    $mod = gmp_mod("8", "3");
    echo gmp_strval($mod) . "\n";// 2

转载于:https://www.cnblogs.com/XiongMaoMengNan/p/8087962.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值