分类 PHP 下的文章

    四则运算表达式,我们书面使用的叫做中缀表达式,而计算器,却更加喜欢后缀表达,括号优先级,加减乘除优先级等使得运算中缀四则表达式变得困难。这个时候引入了一种计算机喜欢的格式,叫做后缀表达式。本文以PHP代码,实现中缀表达式转后缀表达式的逻辑。

    本文以PHP为代码环境,有人会说高级语言直接写表达式就好了,它们会算,可是他们为什么会算,怎么算的,还是需要把中缀表达式转为后缀表达式。因此本文代码只是模拟一个逻辑。

    比如:传统的四则运算表达式(中缀表达式)是9 + ( 3 - 1 ) * 3 + 10 / 2,对应的后缀表达式就是9 3 1 - 3 * + 10 2 / +。

    转换逻辑:一个字符一个字符的输入,如果是数字则直接输出;如果是左括号则直接入栈;如果是右括号则开始出栈,直到遇到第一次左括号为止;如果是加减乘除,则判断,如果栈顶也是符号,且输入的符号的优先级不高于栈顶的符号优先级,则全部出栈,否则该输入的符号入栈。

<?php

/**

 * 将输入的字符按照中缀表达式转后缀表达式的规则处理

 * @param $str 输入的字符

 * @param $stack 栈

 * @param $newStrList 新的表达式

 */

function suffix($str, &$stack, &$newStrList){

    //如果是数字则输出

    if(is_numeric($str)){

        $newStrList .= $str . ' ';

    }

    //如果是左括号则入栈

    else if($str == '('){

        $stack[] = $str;

    }

    //如果是右括号则将最近的左括号之前的所有数据出栈

    else if($str == ')'){

        while($arrPop = array_pop($stack)){

            if($arrPop == '('){

                break;

            }

            $newStrList .= $arrPop . ' ';

        }

    }

    //如果是加减乘除则判断与栈顶符号优先级

    else if(in_array($str, array('+', '-', '*', '/')) && count($stack) > 0){

        $key  = (count($stack) - 1);

        if(in_array($stack[$key], array('+', '-', '*', '/'))){

            //该符号优先级不高于栈顶符号的

            if(checkPriority($str, $stack[$key]) != 1){

                for($i=$key; $i>=0; $i--){

                    if($stack[$i] == '('){

                        break;

                    }

                    $newStrList .= $stack[$i] . ' ';

                    unset($stack[$i]);

                    $stack = array_values($stack);

                }

            }

        }

        //本次的符号入栈

        $stack[] = $str;

    }else{

        $stack[] = $str;

    }

}


/**

 * 判断运算符的优先级

 * @param $operatorA

 * @param $operatorB

 * @return A大于B返回1,A等于B返回0,A小于B返回-1

 */

function checkPriority($operatorA, $operatorB){

    switch($operatorA){

        case '+':

        case '-':

            if($operatorB == '+' || $operatorB == '-'){

                return 0;

            }else if($operatorB == '*' || $operatorB == '/'){

                return -1;

            }

            break;

        case '*':

        case '/':

            if($operatorB == '+' || $operatorB == '-'){

                return 1;

            }else if($operatorB == '*' || $operatorB == '/'){

                return 0;

            }

            break;

        default:

            exit('error');

    }

}

//栈

$stack = array();

//待转换的表达式

$strList = '9 + ( 3 - 1 ) * 3 + 10 / 2';

//新的表达式

$newStrList = '';

$strList = explode(' ', $strList);

foreach($strList as $str){

    if($str != ' '){

        suffix($str, $stack, $newStrList);

    }

}

//数组反转

while($s = array_pop($stack)){

    $newStrList .= $s . ' ';

}

echo $newStrList;


XHProf是Facebook开发的性能调试工具,帮助我们的PHP程序性能调优,更加健壮。XHProf安装和使用方法将在本章讲解。XHProf是PHP的PECL扩展。没有XDeBug那些耗费资源,更加的小巧。
流程:程序开头打点,结尾打点。那么XHProf机会记录在两个点之间的所有代码响应时所耗费的时间、内存、CPU等各项指标,我们也可以知道一次请求调用了多少次MySQL,多少次Memcache,更加直观的指明优化道路。
安装:

------------下载并编译PHP-XHProf源码------------
wget http://pecl.php.net/get/xhprof-0.9.4.tgz
tar -zxvf xhprof-0.9.4.tgz
cd xhprof-0.9.4
cd extension
phpize
./configure --enable-xhprof
make
make test
sudo make install

------------修改php.ini---------------
sudo vim /etc/php.ini
#在php.ini最下方加入以下:
extension=xhprof.so
xhprof.output_dir="/var/www/xhprof"

-----------重启Apache--------------
sudo apache restart

进入刚才解压的安装包文件夹中,将xhprof_lib和xhprof_html复制到项目目录下。
接下来,建立一个头文件head.php,这是要打两个点中的开头的点:

//head.php
<?php
if(extension_loaded('xhprof')){
    //载入下载的XHPROF包中的2个文件夹
    include_once 'xhprof_lib/utils/xhprof_lib.php';
    include_once 'xhprof_lib/utils/xhprof_runs.php';
    xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}

再建立一个底部文件foot.php,这是要打两个点中的结尾的点:

//foot.php
<?php
if(extension_loaded('xhprof')){
    $ns = 'myXhprof';
    //关闭profiler
    $xhprofData = xhprof_disable();
    //实例化类
    $xhprofRuns = new XHProfRuns_Default();
    $runId = $xhprofRuns->save_run($xhprofData, $ns);
    //前端展示库的URL
    $url = 'http://localhost/xhprof_html/index.php';
    $url .= '?run=%s&source=%s';
    //变量替换
    $url = sprintf($url, $runId, $ns);
    //输入URL
    echo '<a href="'.$url.'" target="_blank">查看结果</a>';
}

使用的最后一步:打点。现在我们建立一个测试文件index.php。测试我大Hello World。

//index.php
<?php
include_once 'head.php';
echo 'Hello World';
include_once 'foot.php';

可以看到,在http://localhost/index.php中,最下面是我们在foot.php中写的“查看结果”,点击进去,可以看到本次请求所使用到的所有函数的列表,每个函数所耗费的时间、CPU、Memory等信息,点击第一栏可以根据所选排序。点击[View Full Callgraph]可以看到由本列表所生成的流程图,从入口到哪个函数,又到哪个函数,这个函数调用了哪个函数,这个函数调用了多少次Memcache等,一幕了然。减少MC的调用,减少这个,减少那个,请求的响应速度能不快吗?

技巧:
我有1000个文件,现在我需要用XHProf检测一下我整个项目,难道要每个文件头部和尾部都要加上include吗?
在php.ini中添加:

auto_prepend_file = /var/www/head.php
auto_append_file = /var/www/foot.php

或者在.htaccess中添加

php_value auto_prepend_file = /var/www/head.php
php_value auto_append_file = /var/www/foot.php

报错:
1、点击[View Full Callgraph]查看图片的时候报错:failed to execute cmd:" dot -Tpng". stderr:`sh: dot:command not found`。
原因:原因:未安装图形化工具
解决:

//红帽系列
yum install graphviz
//Ununtu
apt-get install graphviz
//OS X
brew install graphviz

PHP命名空间是PHP5.3开始支持。本篇讲解PHP命名空间用法和PHP命名空间详解。它的诞生使的我们在一个文件中可以使用多个同名的类而不冲突。
好处:我们的项目有一个记录日志文件的类,叫做Log。然后我们又必须要引入另一个代码包,这个代码包里也有一个叫做Log的类。那么在一个文件中,我们记录日志的又需要给两个类都写一条日志。可以类同名了,怎么办?这个时候,命名空间应运而生。在Java等语言中命名空间是很早就已经提供了支持,而我大PHP一直到5.3才对命名空间提供了支持。
示例一:
文件index.php

<?php
include 'test.php';

class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}
$obj = new index();
$obj->a();
echo '<br>';
$obj1 = new test\index();
$obj1->a();
?>

文件test.php

<?php
namespace test;
class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}
?>

我们给index.php不设置命名空间,对test.php设置命名空间,名为test。运行index.php。
结果:

index.php
index : index::a
test.php
test\index : test\index::a

我们看到了,同名的类也可以运行而不冲突了。

示例二:
文件index.php

<?php
namespace index;
include 'test.php';

class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}
$obj = new index();
$obj->a();
echo '<br>';
$obj1 = new \test\index();
$obj1->a();
?>

文件test.php

<?php
namespace test;
class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}
?>

我们给index.php设置命名空间,名为index,对test.php设置命名空间,名为test。运行index.php。
结果:

index.php
index\index : index\index::a
test.php
test\index : test\index::a

比较示例一和二,不对index.php设置命名空间,即该文件是整个PHP全局命名空间下面的一个文件,那么使用test\index()即可,如果对index.php设置命名空间,即在其他的命名空间中使用命名空间,就要多一个“\”,就要使用\test\index()。

示例三:
文件index.php

<?php
namespace index;

include 'namespace.php';

use \test\test1\test2 as test2;

class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}

$obj = new index();
$obj->a();

echo '<br>';

$obj1 = new \test\test1\test2\index();
$obj1->a();

echo '<br>';

$obj1 = new test2\index();
$obj1->a();

文件test.php

<?php
namespace test\test1\test2;
class index{
    public function a(){
        echo basename(__FILE__);
        echo '<br>';
        echo __CLASS__ . ' : ' . __METHOD__;
    }
}

结果:

index.php
index\index : index\index::a
test.php
test\test1\test2\index : test\test1\test2\index::a
test.php
test\test1\test2\index : test\test1\test2\index::a

这说明了什么?别名!用过SQL吧。

select COUNT(*) as `count` from `tebleName`

嗯,一个意思。\test\test1\test2这个名字太长了,就别名为test2就好了。使用了use之后呢,这个命名空间就想到于是在index这个命名空间下面了,而不是全局命名空间的一员了,所以使用test2\index(),而不是\test2\index()。

别名时在PHP代码编译的时候执行的,而变量的解析则要更晚。也就是说不能对变量运用use关键字。示例如下(摘自官方手册示例):

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a;      // 实际化一个 Another 对象

用文件的方式读写,一个文件是索引文件,另一个文件是真实的数据文件。
索引文件分为2部分,第一部分是所有的指针,记录第二部分的位置;第二部分是索引记录。所有的索引指针:是记录所有相同Hash值的key的指针,它是一个链表结构,记录在数据文件的位置和同key的下一个值。
索引记录中:每条记录有四部分,第一部分4个字节,是下一条索引的偏移量;第二部分是该记录的key,128字节;第三部分是数据偏移量,4个字节;第四部分是数据记录长度,4个字节。
我们设定文件的存储上限为262144个。

查找流程如下:
1、根据key算出hash值,获取该hash值的链表在索引文件的第一部分(所有指针区)的位置。
2、根据步骤一的位置,获取值,时间复杂度O(1);
2、根据步骤一中的值,找到索引文件中第二部分(索引记录)的位置,也就是和key相同hash值的所有指针的链表。顺着链表查找该key,获取该key在链表中存放的数据,数据只包含该key在索引文件中的位置,时间复杂度为O(n);
3、根据步骤二所获取的key在索引文件位置,得到索引文件中存放该key的信息。信息包含在真实数据文件中存放真实数据的位置。
4、根据步骤三所获取的位置,在真实数据文件中获取数据,并返回给应用程序。

测试结果:插入10000条耗时:793ms。查找10000条耗时:149ms。虽然这效率只有Redis的十分之一。。。但是请不要在意这些细节。。。

代码做了注释,上述文字有些乱。代码只实现三个方法,一个插入(如果存在则跳过),一个是查找,一个是删除。

思路来源:《PHP核心技术与最佳实践》一书。尊重作者,转载请保留该书名。

<?php
//Hash表中的元素指针个数,每个指针都是int,存储hash链表的文件偏移量
define('DB_BUCKET_SIZE', 262144);
//每条记录的key的长度
define('DB_KEY_SIZE', 128);
//一条索引记录的长度
define('DB_INDEX_SIZE', DB_KEY_SIZE + 12);

//成功-返回码
define('DB_SUCCESS', 1);
//失败-返回码
define('DB_FAILURE', -1);
//key重复-返回码
define('DB_KEY_EXISTS', -2);

class DB{
    private $idx_fp;
    private $dat_fp;
    private $closed;

    /**
     * Description: 打开数据库
     * @param $pathName 数据文件的存放路径
     * @return mixed
     */
    public function open($pathName){
        $idx_path = $pathName . '.idx';
        $dat_path = $pathName . '.dat';
        if(!file_exists($idx_path)){
            $init = true;
            $mode = "w+b";
        }else{
            $init = false;
            $mode = 'r+b';
        }
        $this->idx_fp = fopen($idx_path, $mode);
        if(!$this->idx_fp){
            return DB_FAILURE;
        }
        if($init){
            //把0x00000000转换成无符号长整型的二进制
            $elem = pack('L', 0x00000000);
            for($i=0; $i< DB_BUCKET_SIZE; $i++){
                fwrite($this->idx_fp, $elem, 4);
            }
        }
        $this->dat_fp = fopen($dat_path, $mode);
        if(!$this->dat_fp){
            return DB_FAILURE;
        }

        return DB_SUCCESS;
    }

    /**
     * Description: Times33 Hash算法
     * @param $key
     * @return int
     */
    private function times33Hash($key){
        $len = 8;
        $key = substr(md5($key), 0, $len);
        $hash = 0;
        for($i=0; $i<$len; $i++){
            $hash += 33 * $hash + ord($key[$i]);
        }
        //0x7FFFFFFF:一个十六进制的数是4bit,8个就是32位,就是4字节,和一个int一样大。而F是1111,7是0111,那么这个十六进制的数就是头为0,其余为1的,首位是符号位,也就是说7fffffff是最大的整数。
        //& 0x7fffffff 可以保证返回的数是正整数
        return $hash & 0x7FFFFFFF;
    }

    /**
     * Description: 插入记录
     * @param $key
     * @param $value
     */
    public function add($key, $value){
        $offset = ($this->times33Hash($key) % DB_BUCKET_SIZE) * 4;

        $idxoff = fstat($this->idx_fp);
        $idxoff = intval($idxoff['size']);

        $datoff = fstat($this->dat_fp);
        $datoff = intval($datoff['size']);

        $keylen = strlen($key);
        $vallen = strlen($value);
        if($keylen > DB_KEY_SIZE){
            return DB_FAILURE;
        }
        //0表示这是最后一个记录,该链再无其他记录。
        $block = pack('L', 0x00000000);
        //键值
        $block .= $key;
        //如果键值的长度没有达到最大长度,则用0填充
        $space = DB_KEY_SIZE - $keylen;
        for($i=0; $i<$space; $i++){
            $block .= pack('C', 0x00);
        }
        //数据所在文件的偏移量
        $block .= pack('L', $datoff);
        //数据记录的长度
        $block .= pack('L', $vallen);
        //尽管SEEK_SET是默认值,但是显式声明了就不怕以后官方会改变了-.-
        fseek($this->idx_fp, $offset, SEEK_SET);
        //检测该key所对应的hash值是否存在了
        $pos = @unpack('L', fread($this->idx_fp, 4));
        $pos = $pos[1];
        //如果key不存在
        if($pos == 0){
            fseek($this->idx_fp, $offset, SEEK_SET);
            fwrite($this->idx_fp, pack('L', $idxoff), 4);

            fseek($this->idx_fp, 0, SEEK_END);
            fwrite($this->idx_fp, $block, DB_INDEX_SIZE);

            fseek($this->dat_fp, 0, SEEK_END);
            fwrite($this->dat_fp, $value, $vallen);

            return DB_SUCCESS;
        }
        //如果key存在
        $found = false;
        while($pos){
            fseek($this->idx_fp, $pos, SEEK_SET);
            $tmp_block = fread($this->idx_fp, DB_INDEX_SIZE);
            $cpkey = substr($tmp_block, 4, DB_KEY_SIZE);
            //$cpkey==$key时返回0,小于返回负数,大于返回正数
            if(!strncmp($cpkey, $key, $keylen)){
                $dataoff = unpack('L', substr($tmp_block, DB_KEY_SIZE + 4, 4));
                $dataoff = $dataoff[1];
                $datalen = unpack('L', substr($tmp_block, DB_KEY_SIZE + 8, 4));
                $datalen = $datalen[1];
                $found = true;
                break;
            }
            $prev = $pos;
            $pos = @unpack('L', substr($tmp_block, 0, 4));
            $pos = $pos[1];
        }

        if($found){
            return DB_KEY_EXISTS;
        }
        fseek($this->idx_fp, $prev, SEEK_SET);
        fwrite($this->idx_fp, pack('L', $idxoff), 4);
        fseek($this->idx_fp, 0, SEEK_END);
        fwrite($this->idx_fp, $block, DB_INDEX_SIZE);
        fseek($this->dat_fp, 0, SEEK_END);
        fwrite($this->dat_fp, $value, $vallen);
        return DB_SUCCESS;
    }

    /**
     * Description: 查询一条记录
     * @param $key
     */
    public function get($key){
        //计算偏移量,key的hash值对索引文件的大小求模,再乘4。因为每个链表指针大小为4
        $offset = ($this->times33Hash($key) % DB_BUCKET_SIZE) * 4;
        //SEEK_SET是默认的
        fseek($this->idx_fp, $offset, SEEK_SET);
        $pos = unpack('L', fread($this->idx_fp, 4));
        $pos = $pos[1];

        $found = false;
        while($pos){
            fseek($this->idx_fp, $pos, SEEK_SET);
            $block = fread($this->idx_fp, DB_INDEX_SIZE);
            $cpkey = substr($block, 4, DB_KEY_SIZE);

            if(!strncmp($key, $cpkey, strlen($key))){
                $dataoff = unpack('L', substr($block, DB_KEY_SIZE + 4, 4));
                $dataoff = $dataoff[1];

                $datalen = unpack('L', substr($block, DB_KEY_SIZE + 8, 4));
                $datalen = $datalen[1];

                $found = true;
                break;
            }
            $pos = unpack('L', substr($block, 0, 4));
            $pos = $pos[1];
        }
        if(!$found){
            return null;
        }
        fseek($this->dat_fp, $dataoff, SEEK_SET);
        $data = fread($this->dat_fp, $datalen);
        return $data;
    }

    /**
     * Description: 删除
     * @param $key
     */
    public function delete($key){
        $offset = ($this->times33Hash($key) % DB_BUCKET_SIZE) * 4;
        fseek($this->idx_fp, $offset, SEEK_SET);
        $head = unpack('L', fread($this->idx_fp, 4));
        $head = $head[1];
        $curr = $head;
        $prev = 0;
        $found = false;
        while($curr){
            fseek($this->idx_fp, $curr, SEEK_SET);
            $block = fread($this->idx_fp, DB_INDEX_SIZE);

            $next = unpack('L', substr($block, 0, 4));
            $next = $next[1];

            $cpkey = substr($block, 4, DB_KEY_SIZE);
            if(!strncmp($key, $cpkey, strlen($key))){
                $found = true;
                break;
            }
            $prev = $curr;
            $curr = $next;
        }
        if(!$found){
            return DB_FAILURE;
        }
        //删除索引文件。
        if($prev == 0){
            fseek($this->idx_fp, $offset, SEEK_SET);
            fwrite($this->idx_fp, pack('L', $next), 4);
        }else{
            fseek($this->idx_fp, $prev, SEEK_SET);
            fwrite($this->idx_fp, pack('L', $next), 4);
        }
        return DB_SUCCESS;
    }

    public function close(){
        if(!$this->closed){
            fclose($this->idx_fp);
            fclose($this->dat_fp);
            $this->closed = true;
        }
    }
}
?>

测试,测试添加一万条和查找一万条:

<?php
//先include上面的类。。如果在同一个文件中就不用了。
//测试
$db = new DB();
$db->open('/var/www/data/');

$startTime = microtime(true);

//插入测试...插入10000条:成功,耗时: 793.48206520081ms
//for($i=0; $i<10000; $i++){
//    $db->add('key'.$i, 'value'.$i);
//}

//查找测试...查找10000条:成功,耗时: 149.08313751221ms
for($i=0; $i<10000; $i++){
    $db->get('key'.$i);
}

$endTime = microtime(true);
echo '成功,耗时: ' . (($endTime - $startTime)*1000) . 'ms';
$db->close();
?>

Hash表作为最重要的数据结构之一,也叫做散列表。使用PHP实现Hash表的功能。PHP可以模拟实现Hash表的增删改查。通过对key的映射到数组中的一个位置来访问。映射函数叫做Hash函数,存放记录的数组称为Hash表。
Hash函数把任意长度的和类型的key转换成固定长度输出。不同的key可能拥有相同的hash。
Hash表的时间复杂度为O(1)

<?php
/**
 * hash表类
 * Class HashTable
 * Auth Lane
 * Mail lixuan868686@163.com
 * Blog http://www.lanecn.com
 */
class HashTable{
    private $arr = array();
    private $size = 10;
    public function __construct(){
        //SplFixedArray创建的数组比一般的Array()效率更高,因为更接近C的数组。创建时需要指定尺寸
        $this->arr = new SplFixedArray($this->size);
    }

    /**
     * Description: 简单hash算法。输入key,输出hash后的整数
     * @param $key
     * @return int
     */
    private function simpleHash($key){
        $len = strlen($key);
        //key中每个字符所对应的ASCII的值
        $asciiTotal = 0;
        for($i=0; $i<$len; $i++){
            $asciiTotal += ord($key[$i]);
        }
        return $asciiTotal % $this->size;
    }

    /**
     * Description: 赋值
     * @param $key
     * @param $value
     * @return bool
     */
    public function set($key, $value){
        $hash = $this->simpleHash($key);
        $this->arr[$hash] = $value;
        return true;
    }

    /**
     * Description: 取值
     * @param $key
     * @return mixed
     */
    public function get($key){
        $hash = $this->simpleHash($key);
        return $this->arr[$hash];
    }

    public function getList(){
        return $this->arr;
    }

    public function editSize($size){
        $this->size = $size;
        $this->arr->setSize($size);
    }
}
?>

下面对我们的HashTable进行测试。

<?php
//测试1
$arr = new HashTable();
for($i=0; $i<15; $i++){
    $arr->set('key'.$i, 'value'.$i);
}
print_r($arr->getList());
//SplFixedArray Object
//(
//    [0] => value14
//    [1] => value4
//    [2] => value5
//    [3] => value6
//    [4] => value7
//    [5] => value8
//    [6] => value10
//    [7] => value11
//    [8] => value12
//    [9] => value13
//)
//不同的key可能产生相同的hash值,那么赋值的时候后操作会覆盖前操作。

//测试2
$arr->editSize(15);
for($i=0; $i<15; $i++){
    $arr->set('key'.$i, 'value'.$i);
}
print_r($arr->getList());
//SplFixedArray Object
//(
//    [0] => value14
//    [1] => value4
//    [2] => value0
//    [3] => value1
//    [4] => value2
//    [5] => value3
//    [6] => value10
//    [7] => value11
//    [8] => value12
//    [9] => value13
//    [10] => value14
//    [11] => value9
//    [12] =>
//    [13] =>
//    [14] =>
//)
?>

改变了值之后可以存放更多的元素。但是仍然存在不同的key可能产生相同的hash值,那么赋值的时候后操作会覆盖前操作的问题。这种冲突的问题我们来用拉链法解决。

拉链法解决冲突。拉链法解决冲突的做法是将所有的相同Hash值的key放在一个链表中,比如key3和key14在hash之后都是0,那么在数组的键为0的地方存储这两个值,形式是链表。如果不能理解我的文字,请看下面的示例,看一下打印信息就明白了。拉链法是什么,就是链表。
创建一个HashNode类,用来存储key和value的值,并且存储相同hash的另一个元素。在同一条链上,查找越后的元素越费时。时间复杂度为O(n).

<?php
class HashNode{
    public $key;
    public $value;
    public $nextNode;
    public function __construct($key, $value, $nextNode=Null){
        $this->key = $key;
        $this->value = $value;
        $this->nextNode = $nextNode;
    }
}
class NewHashTable{
    private $arr;
    private $size = 10;
    public function __construct(){
        $this->arr = new SplFixedArray($this->size);
    }
    private function simpleHash($key){
        $asciiTotal = 0;
        $len = strlen($key);
        for($i=0; $i<$len; $i++){
            $asciiTotal += ord($key[$i]);
        }
        return $asciiTotal % $this->size;
    }
    public function set($key, $value){
        $hash = $this->simpleHash($key);
        if(isset($this->arr[$hash])){
            $newNode = new HashNode($key, $value, $this->arr[$hash]);
        }else{
            $newNode = new HashNode($key, $value, null);
        }
        $this->arr[$hash] = $newNode;
        return true;
    }
    public function get($key){
        $hash = $this->simpleHash($key);
        $current = $this->arr[$hash];
        while(!empty($current)){
            if($current->key == $key){
                return $current->value;
            }
            $current = $current->nextNode;
        }
        return NULL;
    }
    public function getList(){
        return $this->arr;
    }
}
?>

对我们新的HashTable进行测试

<?php
//测试1
$newArr = new NewHashTable();
for($i=0; $i<30; $i++){
    $newArr->set('key'.$i, 'value'.$i);
}
print_r($newArr->getList());
var_dump($newArr->get('key3'));
//SplFixedArray Object
//(
//    [0] => HashNode Object
//(
//    [key] => key23
//            [value] => value23
//            [nextNode] => HashNode Object
//(
//    [key] => key14
//                    [value] => value14
//                    [nextNode] => HashNode Object
//(
//    [key] => key3
//                            [value] => value3
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [1] => HashNode Object
//(
//    [key] => key24
//            [value] => value24
//            [nextNode] => HashNode Object
//(
//    [key] => key15
//                    [value] => value15
//                    [nextNode] => HashNode Object
//(
//    [key] => key4
//                            [value] => value4
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [2] => HashNode Object
//(
//    [key] => key25
//            [value] => value25
//            [nextNode] => HashNode Object
//(
//    [key] => key16
//                    [value] => value16
//                    [nextNode] => HashNode Object
//(
//    [key] => key5
//                            [value] => value5
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [3] => HashNode Object
//(
//    [key] => key26
//            [value] => value26
//            [nextNode] => HashNode Object
//(
//    [key] => key17
//                    [value] => value17
//                    [nextNode] => HashNode Object
//(
//    [key] => key6
//                            [value] => value6
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [4] => HashNode Object
//(
//    [key] => key27
//            [value] => value27
//            [nextNode] => HashNode Object
//(
//    [key] => key18
//                    [value] => value18
//                    [nextNode] => HashNode Object
//(
//    [key] => key7
//                            [value] => value7
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [5] => HashNode Object
//(
//    [key] => key28
//            [value] => value28
//            [nextNode] => HashNode Object
//(
//    [key] => key19
//                    [value] => value19
//                    [nextNode] => HashNode Object
//(
//    [key] => key8
//                            [value] => value8
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [6] => HashNode Object
//(
//    [key] => key29
//            [value] => value29
//            [nextNode] => HashNode Object
//(
//    [key] => key10
//                    [value] => value10
//                    [nextNode] => HashNode Object
//(
//    [key] => key9
//                            [value] => value9
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [7] => HashNode Object
//(
//    [key] => key20
//            [value] => value20
//            [nextNode] => HashNode Object
//(
//    [key] => key11
//                    [value] => value11
//                    [nextNode] => HashNode Object
//(
//    [key] => key0
//                            [value] => value0
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [8] => HashNode Object
//(
//    [key] => key21
//            [value] => value21
//            [nextNode] => HashNode Object
//(
//    [key] => key12
//                    [value] => value12
//                    [nextNode] => HashNode Object
//(
//    [key] => key1
//                            [value] => value1
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//    [9] => HashNode Object
//(
//    [key] => key22
//            [value] => value22
//            [nextNode] => HashNode Object
//(
//    [key] => key13
//                    [value] => value13
//                    [nextNode] => HashNode Object
//(
//    [key] => key2
//                            [value] => value2
//                            [nextNode] =>
//                        )
//
//                )
//
//        )
//
//)
//string(6) "value3"
?>