Category Archives: PHP - Page 2

新版wow解析库

对wow的数据分析已经有很长很长一段时间了. 其数据结构上大致能比较了解. 但是解析工具一直不如心愿. 当wow版本的升级, 很多数据变得多样化起来. 比如

  1. 一条数据中包含了一个子数据集(表现出来的形式是动态栏位).
  2. 有些数据栏位共享一个字节.

等等情况.

根据多年经验, 我对解析工作做了一个初步的改进.

Field

Field 栏位. 每个栏位我都建立了一个class. 用于表达此栏位的状态, 类型以及结构.

所有的栏位都是继承抽象类 AField.

abstract class AField {
    //unpack读取type, 比如Byte=> "b", int32=> "i"
    public $char;
    //读取长度
    public $size;
    //$name 字段名
    //$dynamic 如果位动态栏位,动态key
    //$group 所属父组
    //$primary_key 是否是主键?
    public function __construct($name = "", $dynamic=0, $group = null, $primary_key = false) {
	$this->name = $name;
	$this->dyn = $dynamic;
	$this->group = $group;
	$this->primary_key = $primary_key;
    }
    
    //重新命名栏位名称
    public function rename($name) {
	$this->name = $name;
	return $this;
    }
    
    //magic方法, 获取栏位名称
    public function __tostring(){
	return "[" . get_class($this).": ". $this->name . "]";
    }
}

AField中包含了栏位名称, 动态key, 动态组名, 主键?
接着创建一些基础栏位, 比如ByteField, UnsignedByteField, IntegerField, UnsignedIntegerField, StringField
再继承基础栏位, 延伸出一些特别栏位: IDField, UnknownField

Row

既然栏位已经写完了. 那么这个时候就要将栏目组成一条数组. 那就是Row.
为了能明确的表述该Row的性质, 我为此创建了DBRow. 其中包含了structures(Field集合), 每个栏位的数值.

DB

完成两个基础Field, Row之后. 这个时候就要组成一个抽象的DB.
这个DB是DBC(DB2), WDB的父类. 它包含了文件, 数据结构, 数据导入导出, 数据的读取地址库, 数据的header.
而它的子类就是实现父类这些方法.

结束

从上看来, 现在解析数据更加快捷方便. 同时能应对文章刚开始说的各种情况.

PHP内部Interfaces

可以使用get_declared_interfaces获得当前php中的interface

1. Traversable (遍历接口)
无法单独实现. 比如由 IteratorAggregate 或 Iterator 接口实现

2. IteratorAggregate (聚合式迭代器)
创建一个外部迭代器的接口

IteratorAggregate extends Traversable {
abstract public Traversable getIterator ( void )
}

3. Iterator (迭代器)
可在内部迭代自己的外部迭代器或类的接口。

Iterator extends Traversable {
abstract public mixed current ( void )
abstract public scalar key ( void )
abstract public void next ( void )
abstract public void rewind ( void )
abstract public boolean valid ( void )
}

4. ArrayAccess (数组式访问)
提供像访问数组一样访问对象的能力的接口。

ArrayAccess {
abstract public boolean offsetExists ( mixed $offset )
abstract public mixed offsetGet ( mixed $offset )
abstract public void offsetSet ( mixed $offset , mixed $value )
abstract public void offsetUnset ( mixed $offset )
}

5. Serializable (序列化)
自定义序列化的接口。

实现此接口的类将不再支持 __sleep() 和 __wakeup()。不论何时,只要有实例需要被序列化,serialize 方法都将被调用。它将不会调用 __destruct() 或有其他影响,除非程序化地调用此方法。当数据被反序列化时,类将被感知并且调用合适的 unserialize() 方法而不是调用 __construct()。如果需要执行标准的构造器,你应该在这个方法中进行处理。

Serializable {
abstract public string serialize ( void )
abstract public mixed unserialize ( string $serialized )
}

6. Reflector (反射接口)
反射接口实现导出类

Reflector {
abstract public static string export ( void )
abstract public string __toString ( void )
}

7. RecursiveIterator (递归式迭代)

RecursiveIterator extends Iterator {
//Returns an iterator for the current entry.
public RecursiveIterator getChildren ( void )
//Returns if an iterator can be created fot the current entry.
public bool hasChildren ( void )

abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

8. OuterIterator (外层迭代器)

OuterIterator extends Iterator {

//Returns the inner iterator for the current entry.
public Iterator getInnerIterator ( void )

abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

9. Countable
当使用count函数式, 将被调用

Countable {
abstract public int count ( void )
}

10. SeekableIterator(可寻迭代器)

SeekableIterator extends Iterator {
//seek position
abstract public void seek ( int $position )

abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

11. ArrayObject
Object像array一样工作

ArrayObject implements IteratorAggregate , Traversable , ArrayAccess , Serializable , Countable {

const integer STD_PROP_LIST = 1 ;
const integer ARRAY_AS_PROPS = 2 ;

public __construct ([ mixed $input [, int $flags = 0 [, string $iterator_class = "ArrayIterator" ]]] )
public void append ( mixed $value )
public void asort ( void )
public int count ( void )
public array exchangeArray ( mixed $input )
public array getArrayCopy ( void )
public int getFlags ( void )
public ArrayIterator getIterator ( void )
public string getIteratorClass ( void )
public void ksort ( void )
public void natcasesort ( void )
public void natsort ( void )
public bool offsetExists ( mixed $index )
public mixed offsetGet ( mixed $index )
public void offsetSet ( mixed $index , mixed $newval )
public void offsetUnset ( mixed $index )
public void serialize ( void )
public void setFlags ( int $flags )
public void setIteratorClass ( string $iterator_class )
public void uasort ( callable $cmp_function )
public void uksort ( callable $cmp_function )
public void unserialize ( string $serialized )
}

更详细参考http://us.php.net/manual/zh/intro.spl.php

[php]unpack “N” bug on 64 bit system

这个问题只有在64系统下有问题. 当一个数值为负数时候, unpack后会变成一个超大整数.这是由于PHP_INT_MAX导致的.
32为下的PHP_INT_MAX为 2147483647; 而64位下为9223372036854775807;
如何判断php是运行在64位下?

php -r "echo PHP_INT_SIZE;"

如何返回4为32bit, 8为64bit.

我们看下例子

<?php
$s = -379;
$a = pack("N", $s);//转化后还是正常的.得到 ff ff fe 85

print_r(unpack("N", $a));//在32为解出来的结果正常为-379. 而64bit下则为4294966917
?>

如何解决?
网上找到了这么一个处理办法

/// portably build 64bit id from 32bit hi and lo parts
function _Make64 ( $hi, $lo )
{
// on x64, we can just use int
if ( ((int)4294967296)!=0 )
return (((int)$hi)<<32) + ((int)$lo);// workaround signed/unsigned braindamage on x32 $hi = sprintf ( "%u", $hi ); $lo = sprintf ( "%u", $lo );// use GMP or bcmath if possible if ( function_exists("gmp_mul") ) return gmp_strval ( gmp_add ( gmp_mul ( $hi, "4294967296" ), $lo ) );if ( function_exists("bcmul") ) return bcadd ( bcmul ( $hi, "4294967296" ), $lo );// compute everything manually $a = substr ( $hi, 0, -5 ); $b = substr ( $hi, -5 ); $ac = $a*42949; // hope that float precision is enough $bd = $b*67296; $adbc = $a*67296+$b*42949; $r4 = substr ( $bd, -5 ) + + substr ( $lo, -5 ); $r3 = substr ( $bd, 0, -5 ) + substr ( $adbc, -5 ) + substr ( $lo, 0, -5 ); $r2 = substr ( $adbc, 0, -5 ) + substr ( $ac, -5 ); $r1 = substr ( $ac, 0, -5 ); while ( $r4>100000 ) { $r4-=100000; $r3++; }
while ( $r3>100000 ) { $r3-=100000; $r2++; }
while ( $r2>100000 ) { $r2-=100000; $r1++; }

$r = sprintf ( “%d%05d%05d%05d”, $r1, $r2, $r3, $r4 );
$l = strlen($r);
$i = 0;
while ( $r[$i]==”0″ && $i<$l-1 ) $i++; return substr ( $r, $i ); }list(,$a) = unpack ( "N", "\xff\xff\xff\xff" ); list(,$b) = unpack ( "N", "\xff\xff\xff\xff" ); $q = _Make64($a,$b); var_dump($q); [/php]

[PHP]如何判断array真正的类型

习惯了javascript中的array和object.在php中array又可以是Array也可以是Object(这里的Object 与js的object相同. 并非stdClass的Object). 但是问题来了如何判断他真正的类型.在有些时候, 我们需要它真实的类型.才能做一点事情.
目前我找到一个非常挫的方法.通过判断array头部的key是否为0, array最后一个元素的key是否为count – 1值. 并且同时判断, 他的所有key是否为数字. 缺陷在于如果加入一个数组为array(1, 2 => “c”, 10 => 6, 4=>”1″, 3). 这个时候仍然能通过.
刚刚测试了一下, 如何改动了key值. 后面会根据上面一个key值变化.测试如下:

Array ( [0] => 1 [2] => c [10] => 6 [4] => 5 [11] => 3 )

判断方法: 如果有更好的, 请留贴告诉我.

function getRealArrayType($d){
		if (gettype($d) != "array"){return;}	
		//get realtype
		$realType = "array";
		//array / object
		$count = count($d);
		reset($d);
		//first element key is 0?
		if (key($d) != 0){
			$realType = "object";
		}
		end($d);
                //the last element key is (count - 1)
		if (key($d) != ($count - 1)){
			$realType = "object";
		}

		reset($d);
		while (next($d)){
			$key = key($d);
			if (is_string($key)){
				$realType = "object";
				break;
			}
		}
		reset($d);//reset position
		return $realType;
	}