首页 > 编程技术 > php

PHP SPL标准库 SplFixedArray 介绍及和Array的性能测试

发布时间:2016-11-25 16:18

SPL - Standard PHP Library ,标准PHP类库,本文我们来看看SPL标准库之数据结构SplFixedArray,及SplFixedArray和Array的性能测试对比。

SplFixedArray主要是处理数组相关的主要功能,与普通php array不同的是,它是固定长度的,且以数字为键名的数组,优势就是比普通的数组处理更快。

看看我本机的Benchmark测试:

ini_set('memory_limit','12800M');

for($size = 10000; $size < 10000000; $size *= 4) {
    echo PHP_EOL . "Testing size: $size" . PHP_EOL;
    for($s = microtime(true), $container = Array(), $i = 0; $i < $size; $i++) $container[$i] = NULL;
    echo "Array(): " . (microtime(true) - $s) . PHP_EOL;

    for($s = microtime(true), $container = new SplFixedArray($size), $i = 0; $i < $size; $i++) $container[$i] = NULL;
    echo "SplArray(): " . (microtime(true) - $s) . PHP_EOL;
}


结果如下:

Testing size: 10000
Array(): 0.004000186920166
SplArray(): 0.0019998550415039

Testing size: 40000
Array(): 0.017001152038574
SplArray(): 0.0090007781982422

Testing size: 160000
Array(): 0.050002098083496
SplArray(): 0.046003103256226

Testing size: 640000
Array(): 0.19701099395752
SplArray(): 0.16700983047485

Testing size: 2560000
Array(): 0.75704312324524
SplArray(): 0.67303895950317


通常情况下SplFixedArray要比php array快上20%~30%,所以如果你是处理巨大数量的固定长度数组,还是强烈建议使用。

SplFixedArray类摘要如下:

SplFixedArray  implements Iterator   , ArrayAccess   , Countable   {
    /* 方法 */
    public __construct  ([ int $size  = 0  ] )
    public int count  ( void )
    public mixed current  ( void )
    public static SplFixedArray fromArray  ( array $array  [, bool $save_indexes  = true  ] )
    public int getSize  ( void )
    public int key  ( void )
    public void next  ( void )
    public bool offsetExists  ( int $index  )
    public mixed offsetGet  ( int $index  )
    public void offsetSet  ( int $index  , mixed  $newval  )
    public void offsetUnset  ( int $index  )
    public void rewind  ( void )
    public int setSize  ( int $size  )
    public array toArray  ( void )
    public bool valid  ( void )
    public void __wakeup  ( void )
}


 使用SplFixedArray:

$arr = new SplFixedArray(4);
$arr[0] = 'php';
$arr[1] = 1;
$arr[3] = 'python';

//遍历, $arr[2] 为null
foreach($arr as $v) {
    echo $v . PHP_EOL;
}

//获取数组长度
echo $arr->getSize(); //4

//增加数组长度
$arr->setSize(5);
$arr[4] = 'new one';

//捕获异常
try{
    echo $arr[10];
} catch (RuntimeException $e) {
    echo $e->getMessage();
}




SplFixedArray和Array的性能测试

PHP文档专门说明:

The SplFixedArray class provides the main functionalities of array. The main differences between a SplFixedArray and a normal PHP array is that the SplFixedArray is of fixed length and allows only integers within the range as indexes. The advantage is that it allows a faster array implementation.

所以在处理大型的、以数字为索引的数组时,应该用SplFixedArray来代替普通Array。

下面是测试代码:

<?php
function pr() {
    $params = func_get_args();
    $env = php_sapi_name();
    if ("cli" == $env) {
        foreach ($params as $key => $value) {
            echo $value;
        }
    } else {
        foreach ($params as $key => $value) {
            echo "<pre>";
            print_r($value);
            echo "</pre>";
        }
    }
} // 用来打印输出结果


<?php
require dirname(__FILE__)."/function.php";

for ($size=1000; $size<=50000000; $size*=2) {
    pr(PHP_EOL . "Testing size: $size" . PHP_EOL);
    for($s = microtime(true), $container = Array(), $i = 0; $i < $size; $i++) {
        $container[$i] = NULL;
    }
    pr( "Array(): " . (microtime(true) - $s) . PHP_EOL);

    for($s = microtime(true), $container = new SplFixedArray($size), $i = 0; $i < $size; $i++) {
        $container[$i] = NULL;
    }
    pr("SplArray(): " . (microtime(true) - $s) . PHP_EOL);
}

但是在我的测试机器上,这段代码出现了非常诡异的结果:

http://img.my.csdn.net/uploads/201304/13/1365855461_6895.jpg
暂时想不出来是什么原因:难道是因为虚拟机内存太小,导致最后的SplFixedArray插入时需要不断GC才导致时间太长?

下面我们来看一篇关于php性能分析之php-fpm的慢执行日志slow log文章,希望文章对各位有帮助


众所周知,mysql有slow query log,根据慢查询日志,我们可以知道那些sql语句有性能问题。作为mysql的好搭档,php也有这样的功能。如果你使用php-fpm来管理php的话,你可以通过如下选项开启。

PHP 5.3.3 之前设置如下:

<value name=”request_slowlog_timeout”>5s</value>
<value name=”slowlog”>logs/php-fpm-slowlog.log</value>
PHP 5.3.3 之后设置以下如下:
request_slowlog_timeout = 5s
slowlog = /usr/local/php/log/php-fpm-slowlog.log

说明:

request_slowlog_timeout是脚本超过多长时间 就可以记录到日志文件
slowlog 是日志文件的路径
开启后,如果有脚本执行超过指定的时间,就会在指定的日志文件中写入类似如下的信息:

[19-Dec-2013 16:54:49] [pool www] pid 18575
script_filename = /home/admin/web/htdocs/sandbox_canglong/test/tt.php
[0x0000000003a00dc8] curl_exec() /home/admin/web/htdocs/sandbox_canglong/test/tt.php:2
[0x0000000003a00cd0] exfilter_curl_get() /home/admin/web/htdocs/sandbox_canglong/test/tt.php:6

日志说明:

script_filename 是入口文件

curl_exec() : 说明是执行这个方法的时候超过执行时间的。
exfilter_curl_get() :说明调用curl_exec()的方法是exfilter_curl_get() 。
每行冒号后面的数字是行号。

开启后,在错误日志文件中也有相关记录。如下:

[19-Dec-2013 15:55:37] WARNING: [pool www] child 18575, script ‘/home/admin/web/htdocs/sandbox_canglong/test/tt.php’ (request: “GET /test/tt.php”) executing too slow (1.006222 sec), logging
[19-Dec-2013 15:55:37] NOTICE: child 18575 stopped for tracing
[19-Dec-2013 15:55:37] NOTICE: about to trace 18575
[19-Dec-2013 15:55:37] NOTICE: finished trace of 18575

本文我们来看看PHP自带的session隐患,session文件独占锁引起阻塞的问题,session文件阻塞会影响性能,下面来看看我们的解决方案。

在PHP中,P默认的会话处理器是session.save_handler = files(即文件)。如果同一个客户端同时并发发送多个请求(如ajax在页面同时发送多个请求),且脚本执行时间较长,就会导致session文件阻塞,影响性能。因为对于每个请求,PHP执行session_start(),就会取得文件独占锁,只有在该请求处理结束后,才会释放独占锁。这样,同时多个请求就会引起阻塞。解决方案如下:

(1)修改会话变量后,立即使用session_write_close()来保存会话数据并释放文件锁。

session_start();
 
$_SESSION['test'] = 'test';
session_write_close();
 
//do something



(2)利用session_set_save_handler()函数是实现自定义会话处理。

function open($savePath, $sessionName)
{
    echo 'open is called';
    return true;
}
 
function close()
{
    echo 'close is called';
    return true;
}
 
function read($sessionId)
{
    echo 'read is called';
    return '';
}
 
function write($sessionId, $data)
{
    echo 'write is called';
    return true;
}
 
function destroy($sessionId)
{
    echo 'destroy is called';
    return true;
}
 
function gc($lifetime)
{
    echo 'gc is called';
    return true;
}
 
session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
register_shutdown_function ( 'session_write_close' );
 
session_start();
 
$_SESSION['foo'] = "bar";



当然,在 php 5.4.0之后,你可以通过实现 SessionHandlerInterface 接口或继承 SessionHandler 类来使用。

class MySessionHandler extends SessionHandler  {
 
    public function __construct()
    {
    }
 
    public function open($save_path, $session_id)
    {
    }
 
    public function close()
    {
 
    }
 
    public function create_sid()
    {
    }
 
    public function read($id)
    {
    }
 
    public function write($id, $data)
    {
    }
 
    public function destroy($id)
    {
    }
}
 
$handler = new MySessionHandler();

 
//第2个参数将函数 session_write_close()  注册为 register_shutdown_function()  函数。
session_set_save_handler($handler, true);


你可以对上面的代码进行具体实现和封装,利用mysql或其它内存数据库来管理会话数据。还能解决使用集群时,session数据共享问题。

对于这个php自带的隐患,相信官方过一段时间会有很好的解决办法。

有时我们为了网站安全考虑,我们不允许直接跨域提交form表单数据,如果我们自己有这个需求呢?下面我们来介绍两种跨域的方法解决直接跨域问题。

下面我们来看看两种php跨域提交form的方法

一,通过php curl

    function curlPost($url,$params) 
    { 
     $postData = ''; 
     foreach($params as $k => $v) 
     { 
     $postData .= $k . '='.$v.'&'; 
     } 
     rtrim($postData, '&'); 
     $ch = curl_init(); 
     curl_setopt($ch,CURLOPT_URL,$url); 
     curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); 
     
     curl_setopt($ch,CURLOPT_HEADER, false); 
     curl_setopt($ch, CURLOPT_POST, count($postData)); 
     curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);  
     
     $output=curl_exec($ch); 
     
     curl_close($ch); 
     return $output; 
    } 
     
    echo curlPost("http://test.com",array('name'=>"tank")); 

以前很多人用curl来抓,邮箱的通讯录,不过现在已经不可以了。哈哈。

二,利用jquery form,ajax提交

1,下载jquery.form.js

2,js代码

    $('#testform').submit(function() { 
     $(this).ajaxSubmit({ 
     type: 'post', // 提交方式 get/post 
     dataType:"json",//数据类型 
     url: 'your url', // 需要提交的 url 
     success: function(data) { // data 保存提交后返回的数据,一般为 json 数据 
     // 此处可对 data 作相关处理 
     alert('提交成功!'); 
     } 
     $(this).resetForm(); // 提交后重置表单 
     }); 
     return false; // 阻止表单自动提交事件 
    }); 

3,php代码

    header("Access-Control-Allow-Origin:*"); //跨域权限设置,允许所有 
     
    header("Access-Control-Allow-Origin:http://www.test.com"); //只允许test.com跨域提交数据 

Open Flash Chart多报表我们在许多的网站都会看到这个功能了,今天小编就来为各位介绍Open Flash Chart多报表使用方法吧


将生成好的JSON数据传递给前端,前端通过JS来实现切换效果

例子。

<?php
//
// This is the MODEL section:
//
include '../php-ofc-library/open-flash-chart.php';
$title = new title( date("D M d Y") );
$bar = new bar();
$bar->set_values( array(9,8,7,6,5,4,3,2,1) );
$chart_1 = new open_flash_chart();
$chart_1->set_title( $title );
$chart_1->add_element( $bar );

// generate some random data
srand((double)microtime()*1000000);
$tmp = array();
for( $i=0; $i<9; $i++ )
  $tmp[] = rand(1,10);
$bar_2 = new bar();
$bar_2->set_values( $tmp );
$chart_2 = new open_flash_chart();
$chart_2->set_title( new title( "Chart 2 :-)" ) );
$chart_2->add_element( $bar_2 );

//
// This is the VIEW section:
//
?>
<html>
<head>
<script type="text/javascript" src="js/json/json2.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("open-flash-chart.swf", "my_chart", "350", "200", "9.0.0");
</script>
<script type="text/javascript">
function ofc_ready()
{
    alert('ofc_ready');
}
function open_flash_chart_data()
{
    alert( 'reading data' );
    return JSON.stringify(data_1);
}
function load_1()
{
  tmp = findSWF("my_chart");
  x = tmp.load( JSON.stringify(data_1) );
}
function load_2()
{
  alert("loading data_2");
  tmp = findSWF("my_chart");
  x = tmp.load( JSON.stringify(data_2) );
}
function findSWF(movieName) {
  if (navigator.appName.indexOf("Microsoft")!= -1) {
    return window[movieName];
  } else {
    return document[movieName];
  }
}
    
var data_1 = <?php echo $chart_1->toPrettyString(); ?>;
var data_2 = <?php echo $chart_2->toPrettyString(); ?>;
</script>

</head>
<body>
<p>Open Flash Chart</p>

<div id="my_chart"></div>
<br>
<a href="javascript:load_1()">display data_1</a> || <a href="javascript:load_2()">display data_2</a>
<p>
Don't forget to 'view source' to see how the Javascript JSON data is loaded.
</p>
</body>
</html>

标签:[!--infotagslink--]

您可能感兴趣的文章: