Skip to content

Instantly share code, notes, and snippets.

@luxixing
Last active August 22, 2017 23:43
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save luxixing/7411156 to your computer and use it in GitHub Desktop.
Save luxixing/7411156 to your computer and use it in GitHub Desktop.
PHP从5.3向更高版本升级, 处理好不兼容和变更的部分, 掌握新的特性,此系列内容只针对语言层面,至于zend engine优化,修改,不会影响到PHP开发,且本人能力有限,将不会涉及
<?php
/**
* Excel_XML
*/
/**
* Class Excel_XML
*
* A simple export library for dumping array data into an excel
* readable format. Supports OpenOffice Calc as well.
*
* @author Oliver Schwarz <oliver.schwarz@gmail.com>
*/
class Excel_XML
{
/**
* MicrosoftXML Header for Excel
* @var string
*/
const sHeader = "<?xml version=\"1.0\" encoding=\"%s\"?\>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" xmlns:html=\"http://www.w3.org/TR/REC-html40\">";
/**
* MicrosoftXML Footer for Excel
* @var string
*/
const sFooter = "</Workbook>";
/**
* Worksheet & Data
* @var array
*/
private $aWorksheetData;
/**
* Encoding to be used
* @var string
*/
private $sEncoding;
/**
* write xls file handle resouce
*
*/
private $rHandle = null;
/**
* Constructor
*
* Instanciates the class allowing a user-defined encoding.
*
* @param string $sEncoding Charset encoding to be used
*/
public function __construct($sEncoding = 'UTF-8')
{
$this->sEncoding = $sEncoding;
$this->sOutput = '';
}
/**
* Add a worksheet
*
* Creates a new worksheet and adds the given data to it.
* @param string $title Title of worksheet
* @param array $data 2-dimensional array of data
*/
public function addWorksheet($title, $data)
{
$this->aWorksheetData[] = array(
'title' => $this->getWorksheetTitle($title),
'data' => $data
);
}
/**
* Write workbook to file
*
* Writes the workbook into the file/path given as a parameters.
* The method checks whether the directory is writable and the
* file is not existing and writes the file.
*
* @param string $filename Filename to use for writing (must contain mimetype)
* @param string $path Path to use for writing [optional]
*/
public function writeWorkbook($filename, $path = '')
{
$filename = $this->getWorkbookTitle($filename);
//open file check
if (!$this->rHandle = fopen($path . $filename, 'w+'))
{
throw new Exception(sprintf("Not allowed to write to file %s", $path . $filename));
}
//write header
$sheader = stripslashes(sprintf(self::sHeader, $this->sEncoding)) . "\n";
if (fwrite($this->rHandle, $sheader) === false)
{
throw new Exception(sprintf("Error writing to file %s", $path . $filename));
}
//write coentent
$this->generateWorkbook();
//wirte footer
if (fwrite($this->rHandle, self::sFooter) === false)
{
throw new Exception(sprintf("Error writing to file %s", $path . $filename));
}
fclose($this->rHandle);
return sprintf("File %s written", $path . $filename);
}
/**
* Workbook title correction
*
* Corrects filename (if necessary) stripping out non-allowed
* characters.
*
* @param string $filename Desired filename
* @return string Corrected filename
*/
private function getWorkbookTitle($filename)
{
return preg_replace('/[^aA-zZ0-9\_\-\.]/', '', $filename);
}
/**
* Worksheet title correction
*
* Corrects the worksheet title (given by the user) by the allowed
* characters by Excel.
*
* @param string $title Desired worksheet title
* @return string Corrected worksheet title
*/
private function getWorksheetTitle($title)
{
$title = preg_replace ("/[\\\|:|\/|\?|\*|\[|\]]/", "", $title);
return substr ($title, 0, 31);
}
/**
* Generate the workbook
*
* This is the main wrapper to generate the workbook.
* It will invoke the creation of worksheets, rows and
* columns.
*/
private function generateWorkbook()
{
foreach ($this->aWorksheetData as $item):
$this->generateWorksheet($item);
endforeach;
}
/**
* Generate the Worksheet
*
* The second wrapper generates the worksheet. When the worksheet
* data seems to be more than the excel allowed maximum lines, the
* array is sliced.
*
* @param array $item Worksheet data
* @todo Add a security check to testify whether this is an array
*/
private function generateWorksheet($item)
{
$ssheet= sprintf("<Worksheet ss:Name=\"%s\">\n <Table>\n", $item['title']);
if (fwrite($this->rHandle, $ssheet) === false)
{
throw new Exception(sprintf("Error writing to file"));
}
$i = 0;
foreach ($item['data'] as $k => $v)
{
if($i > 65536)
{
break;
}
$this->generateRow($v);
$i++;
}
if (fwrite($this->rHandle, " </Table>\n</Worksheet>\n") === false)
{
throw new Exception(sprintf("Error writing to file"));
}
}
/**
* Generate the single row
* @param array Item with row data
*/
private function generateRow($item)
{
$row = " <Row>\n";
foreach ($item as $k => $v)
{
$row .= $this->generateCell($v);
}
$row .= " </Row>\n";
if (fwrite($this->rHandle, $row) === false)
{
throw new Exception(sprintf("Error writing to file"));
}
}
/**
* Generate the single cell
* @param string $item Cell data
*/
private function generateCell($item)
{
$type = 'String';
if (is_numeric($item))
{
$type = 'Number';
if ($item{0} == '0' && strlen($item) > 1 && $item{1} != '.')
{
$type = 'String';
}
}
$item = str_replace('&#039;', '&apos;', htmlspecialchars($item, ENT_QUOTES));
return sprintf(" <Cell><Data ss:Type=\"%s\">%s</Data></Cell>\n", $type, $item);
}
/**
* Deconstructor
* Resets the main variables/objects
*/
public function __destruct()
{
unset($this->aWorksheetData);
unset($this->sOutput);
}
}

##PHP 5.4新特性##

掌握

  • traits
    trait的引入,可以扩展class的内容,使class在某种形式上实现了多重继承,更加灵活,trait不能被实例化 举个例子,假设有三个类,男人,女人,人,人是男人和女人的父类,双11购物不是人人都有的行为,放在人 这个父类里显然不合适,我们把双11购物单独定义为一个trait,这个双11购物的trait不能自己驱动,需要被 其他类引用,从而让引用trait的类具有购物行为
    示例代码:

    <?php
    trait Hello {
        public function sayHello() {
                echo 'Hello ' . "\n";
            }
    }
    trait World {
        public function sayWorld() {
                echo 'World' . "\n";
            }
    }
    class MyHelloWorld {
        use Hello, World;
        public function sayExclamationMark() {
                echo '!' . "\n";
            }
    }
    $o = new MyHelloWorld();
    $o->sayHello();
    $o->sayWorld();
    $o->sayExclamationMark();
    

    需要注意的是,trait的继承顺序
    来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法

    当多个trait被同一个类使用的时候,会出现方法冲突的情况,使用关键词insteadof解决
    示例代码:

    <?php
    trait A {
        public function smallTalk() {
            echo 'a';
        }
        public function bigTalk() {
            echo 'A';
        }
    }
    trait B {
        public function smallTalk() {
            echo 'b';
        }
        public function bigTalk() {
            echo 'B';
        }
    }
    class Talker {
        use A, B {
            B::smallTalk insteadof A;
            A::bigTalk insteadof B;
        }
    }
    class Aliased_Talker {
        use A, B {
            B::smallTalk insteadof A;
            A::bigTalk insteadof B;
            B::bigTalk as talk;
        }
    }
    
  • 新增短数组语法

      <?php
      $a = [1, 2, 3, 4];
      $a = ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4];
    
  • 新增支持对函数返回数组的成员访问解析

      <?php
      function foo()
      {
        return array(1,3,4,5);
      }
      $var =foo()[0];
    
  • 现在不管是否设置 short_open_tag php.ini 选项,<?= 将总是可用

  • 新增在实例化时访问类成员

      <?php
      class Test
      {
        public function foo()
        {
          //todo
          return 1;
        }
      }
      $var = (new Test)->foo();
      
    >ps:注意括号
    
  • SESSION 扩展现在能追踪文件的 上传进度 在php.ini中配置session.upload_progress.enabled = On,就会开启文件上传进度跟踪功能

  • max_input_vars 指令
    在php.ini文件中,设定max_input_vars的值,可以控制$_GET、$_POST 和 $_COOKIE的最大长度
    降低构造哈希碰撞进行拒绝服务攻击的可能性

了解

  • 现在闭包支持 $this

  • 现在支持 Class::{expr}() 语法 示例代码:

      <?php
      class Utils
      {
          public static function test1()
          {
              echo 1;
          }
          public static function test2()
          {
              echo 2;
          }
      }
      $m = 'test';
      Utils::{$m . (10-8)}();
      Utils::test2();
    
  • 新增二进制直接量,例如:0b001001101

##PHP 5.5新特性##

掌握

  • opcache集成在php发行包
    opcache实际上是zend公司的Zend Optimizer Plus,功能类同apc
    它的性能优于apc,对opcode进行了优化,关于opcache的更多信息
    请移步鸟哥博客 一个关于Zend O+的小分享
    因此在安装PHP的时候,编译参数一定要加上

      --enabled-opcache
      
      推荐配置(php.ini)
      zend_extension=opcache.so
      opcache.enable_cli=1
      opcache.memory_consumption=128      //共享内存大小, 这个根据你们的需求可调
      opcache.interned_strings_buffer=8   //interned string的内存大小, 也可调
      opcache.max_accelerated_files=4000  //最大缓存的文件数目
      opcache.revalidate_freq=60          //60s检查一次文件更新
      opcache.fast_shutdown=1             //打开快速关闭, 打开这个在PHP Request Shutdown的时候,回收内存的速度会提高
      opcache.save_comments=0             //不保存文件/函数的注释
    
  • 生成器(Generators)
    熟悉python的同学对生成器肯定不会陌生的 其功能是在函数中使用关键词yield,中断函数执行并返回一个能在foreach中使用的迭代器 这个语法应该是PHP5.5中最令人激动的特性了 下面的代码演示了生成器用法,并且做了对比,用来突出生成器的优势

    <?php
    ini_set('memory_limit', '512M');
    $cmd = isset($argv[1]) ? (int)$argv[1] : 0;
    
    function xrange($start, $end, $step = 1)
    {
        if($start <= $end)
        {
            if($step <= 0)
            {
                throw new LogicException('step must be +ve');
            }
            for($i = $start; $i <= $end; $i = $i + $step)
            {
                yield $i;
            }
        }else{
            if($step >= 0)
            {
                throw new LogicException('step must be -ve');
            }
            for($i = $start; $i >= $end; $i = $i + $step)
            {
                yield $i;
            }
        }
    }
    
    if($cmd == 0)
    {
        $r = range(1, 1000000);
        foreach($r as $v)
        {
            if($v > 20)
            {
                break;
            }
            echo "$v\t";
        }
        $m = memory_get_usage(true);
        echo "\n" . $m/1014/1024 . "M\n";
    }else if($cmd == 1){
        $r = xrange(1, 1000000);
        foreach($r as $v)
        {
            if($v > 20)
            {
                break;
            }
            echo "$v\t";
        }
        $m = memory_get_usage(true);
        echo "\n" . $m / 1014 /1024 . "M\n";
    }else{
        include 'php-excel.class.php';
        $stime = microtime(true);
        if($cmd == 3)
        {
            $data = array();
            for($i = 0; $i < 10000;$i++)
            {
                $data[] = range(1,100);
            }
            $xls = new Excel_XML();
            $xls->addWorksheet('test', $data);
            $xls->writeWorkbook('test.xls', './');
        }else{
            $data = function($n = 10000){
                for($i = 0; $i < $n; $i++)
                {
                    yield xrange(1,100);
                }
            };
            $xls = new Excel_XML();
            $xls->addWorksheet('test', $data());
            $xls->writeWorkbook('test.xls', './');
        }
        $ctime = microtime(true) - $stime;
        $m = memory_get_usage(true);
        echo "\n" . $m / 1014 /1024 . "M\n";
        echo "cost time:" . $ctime . "s\n";
    }
    

    ps:php-excel.class.php文件内容请参考本gist php-excel.php

  • 新增 finally 关键字 示例代码:

    <?php
    function getLines($file) 
    {
        $f = fopen($file, 'r');
        try 
        {
            while ($line = fgets($f))
            {
                yield $line;
            }
        } finally {
            fclose($f);
        }
    }
    foreach(getLines('finally.php') as $v)
    {
        echo $v;
    }
    

    编写代码的时候,一定要养成良好的习惯,及时的释放打开的资源

  • password API
    password系列函数,为我们存储密码,实现了更简便安全的方式
    密码的存储从明文到md5到md5+salt,到mcrpty+salt password_hash默认使用bcrypt加密算法,自动生成salt,加密密码 示例代码

    <?php
    $pw1 = '123456';
    $pwdb = password_hash($pw1, PASSWORD_DEFAULT);
    var_dump($pwdb) . "\n";
    var_dump(password_verify($pw1, $pwdb)) . "\n";
    $pw2 = '778920';
    $pwdb = password_hash($pw2, PASSWORD_DEFAULT);
    var_dump($pwdb) . "\n";
    var_dump(password_verify($pw1, $pwdb)) . "\n";
    

    强烈建议新应用开发密码存储使用内置password系列函数

  • array_column
    这个函数早就应该有了
    我们从数据库中取出10条记录,想要拿到这十条记录中的指定某一列,之前只能foreach了 现在只需要一个array_coulum函数搞定,这个函数实际意义很大,单独提出来讲了 示例代码:

    <?php
    // Array representing a possible record set returned from a database
    $records = array(
        array(
            'id' => 2135,
            'first_name' => 'John',
            'last_name' => 'Doe',
        ),
        array(
            'id' => 3245,
            'first_name' => 'Sally',
            'last_name' => 'Smith',
        ),
        array(
            'id' => 5342,
            'first_name' => 'Jane',
            'last_name' => 'Jones',
        ),
        array(
            'id' => 5623,
            'first_name' => 'Peter',
            'last_name' => 'Doe',
        )
    );
    $first_names = array_column($records, 'first_name');
    print_r($first_names);
    

熟悉

  • foreach 现在支持 list()

      <?php
      $arr= array(
        array(1,2,3),
        array(1,2,3),
        array(1,2,3),
      );
      foreach($arr as list($a, $b, $c))
      {
        //todo
      }
    
    >ps:需要注意的是,遍历数组的子数组个数要一样
    
  • empty() 支持任意表达式,函数调用也可以使用empty了

了解

  • 改进 GD
    翻转支持使用新的 imageflip() 函数
    高级裁剪支持使用 imagecrop() & imagecropauto() 函数
    WebP 的读写分别支持使用 imagecreatefromwebp() & imagewebp()
另外PHP5.4和PHP5.5新增的function,新增的class,新增的interface,新增的全局常量还是挺多的  
想了解的,可以查看下面链接  
http://www.php.net/manual/zh/migration55.new-functions.php  
http://www.php.net/manual/zh/migration55.classes.php  
http://www.php.net/manual/zh/migration55.new-methods.php  
http://www.php.net/manual/zh/migration55.global-constants.php 
http://www.php.net/manual/zh/migration54.functions.php  
http://www.php.net/manual/zh/migration54.classes.php  
http://www.php.net/manual/zh/migration54.methods.php  
http://www.php.net/manual/zh/migration54.global-constants.php 

##PHP 5.4不兼容内容##

熟悉

  • 安全模式的移除(safe_mode),涉及到php.ini配置指令
    安全模式开启,限制PHP中的一些内置函数的使用
    代码中如果有依赖于安全模式保障安全的内容,需要调整

  • 移除魔术引号(magic_quote),涉及到php.ini配置指令
    魔术引号自动对用户提交数据转义(包括不必要转义的数据),性能低下 魔术引号的效果和使用 addslashes() 函数一样 为避免出现安全问题,任何依赖魔术引号特性的代码都需要修改 移除模式引号后,对仅需要存储到数据库中的数据进行*addslashes()*操作

  • 调用时的引用传递被移除

      <?php
      function foo(&$var)
      {
      	$var = 'hello, word';
      	var_dump($var);
      }
      $var = 1111;
      foo($var);//正确的调用方法
      foo(&$var);//过期用法,报出一个警告错误
      ?>
    
  • 在日期与时间扩展中,不再支持时区使用 TZ(TimeZone)环境变量设置
    php.ini中强烈建议配置date.timezone
    或者在程序入口脚本配置环境时,使用date_default_timezone_set()设定时区

  • 数组转换成字符串将产生一条 E_NOTICE 级别的错误,但返回的结果仍是字符串 "Array"

  • 现在参数名使用全局变量将会导致一个致命错误

      <?php
      //这样的代码,报致命错误 
      function foo($_GET, $_POST) {};
    
  • 当使用两个空数组作为参数时, array_combine() 现在返回 array() 而不是 FALSE

  • trait,callable,insteadof成为新的保留字,在函数和类名中不可使用

了解

  • register_globals 和 register_long_arrays php.ini 指令被移除

  • break 和 continue 语句不再接受可变参数

      <?php
      define('VAR', 10);
      while(true)
      {
        while(true)
        {
          //正确写法
          break 10;
          continue VAR;
          //错误写法
          break 10 - $var;
          contnue $var * 10;
        }
      }
    
  • NULL 、FALSE 、或 一个空字符串被添加成一个对象的属性时将发出一条 E_WARNING 级别的错误,而不是 E_STRICT

  • Salsa10 和 Salsa20 哈希算法 被移除

  • 强烈建议不要再使用 eregi()

  • 移除的函数

        define_syslog_variables() 
        import_request_variables()  
        session_is_registered() 、 session_register() 以及 session_unregister() 
        mysqli_bind_param() 、 mysqli_bind_result() 、 mysqli_client_encoding()
        mysqli_fetch() 、 mysqli_param_count() 、 mysqli_get_metadata() 
    
  • 过时的函数

      mcrypt_generic_end()  
      mysql_list_dbs()  
    
  • sqlite扩展被移到 pecl扩展中,不包含在PHP发行版中

##PHP5.5不兼容内容##

熟悉

  • 原始的 MySQL 扩展 现在被废弃(不推荐使用,下版本将会移除)
    当连接到数据库时会产生一个 E_DEPRECATED 错误。可使用 MySQLi 或 PDO_MySQL 扩展作为替代

了解

  • windows xp & windows server 2003支持取消。还在使用这两个环境就太out了

  • 移除 PHP logo GUIDs组函数
    php_logo_guid()
    php_egg_logo_guid()
    php_real_logo_guid()
    zend_logo_guid()

  • preg_replace() 中的 /e 修饰符被标识为不推荐使用
    替代方案是使用 preg_match_replace

  • mcrypt 中的下列函数过期(在未来版本会被移除)

      mcrypt_cbc()  
    	mcrypt_cfb()  
    	mcrypt_ecb()  
    	mcrypt_ofb()  
    
  • intl 中的废弃
    IntlDateFormatter::setTimeZoneID() 和 datefmt_set_timezone_id() 现在被废弃 可分别使用 IntlDateFormatter::setTimeZone() 方法和 datefmt_set_timezone() 函数作为替代

  • pack() 和 unpack() 函数的变化 添加了Z格式和perl兼容 这两个函数在二进制接口使用

##PHP5.4-5.5变更##

ps:本部分内容不再具体区分版本号

  • mysqlnd
    mysql mysqli及PDO_mysql现在使用mysqlnd作为默认库 强烈建议使用mysqlnd库和PDO_mysql
    在编译安装PHP的时候,加上如下参数

      --enable-mysqlnd --with-mysqli --with-pdo-mysql
    
  • intl 扩展现在需要 ICU 4.0 或更高版本

  • pdo_mysql不再支持使用低于 4.1 版本的 MySQL 客户端库连接

更多变更请访问下面的资源

  http://www.php.net/manual/zh/migration54.parameters.php
  http://www.php.net/manual/zh/migration55.changed-functions.php
  http://www.php.net/manual/zh/migration54.ini.php
  http://www.php.net/manual/zh/migration55.ini.php

上面的变更主要是函数参数和php.ini配置指令在php5.4,php5.5中的变化 其中一些变更
和新增特性,不兼容部分有交叉

@luxixing
Copy link
Author

求反馈

@wenjun1055
Copy link

不错哦,支持

@lgl5240
Copy link

lgl5240 commented Nov 12, 2013

一直希望有这种资料,支持楼主。

@luxixing
Copy link
Author

@wenjun1055 多谢

@wangjuqingsd
Copy link

好样的

@jeyzhu
Copy link

jeyzhu commented Oct 11, 2014

Good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment