Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link
Owner Author

@luxixing luxixing commented Nov 12, 2013

求反馈

@wenjun1055

This comment has been minimized.

Copy link

@wenjun1055 wenjun1055 commented Nov 12, 2013

不错哦,支持

@lgl5240

This comment has been minimized.

Copy link

@lgl5240 lgl5240 commented Nov 12, 2013

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

@luxixing

This comment has been minimized.

Copy link
Owner Author

@luxixing luxixing commented Nov 12, 2013

@wenjun1055 多谢

@wangjuqingsd

This comment has been minimized.

Copy link

@wangjuqingsd wangjuqingsd commented Nov 18, 2013

好样的

@jeyzhu

This comment has been minimized.

Copy link

@jeyzhu jeyzhu commented Oct 11, 2014

Good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.