搬家到http://reeze.cn/

yo2的服务质量是在堪忧啊。。 前一阵后台根本就进不来。
算了用自己的空间吧。、
reeze

Posted in 未分类 | Leave a comment

新设计的博客首页

给自己的博客设计了一个新的界面,大概是定型了。。不想做了,明天还得上班,rblog还没有写好,不知道什么时候我的个人网站能上线啊。。

home

Posted in 未分类 | Leave a comment

基于var_export 和 include返回值的缓存方案

前一篇文章我们研究了include调用返回值的问题,并指出可以通过这种方式来完成序列化相同的功能,现在我就来研究一下这种方法的可行性和效率,因为直接的返回php值肯定是比unserialize()函数要快。

第一步我们来研究下怎么将php对象持久化的保存起来。下面是我定义的一些变量:
<?php

class MyClass {
private $_var;
public  $pub  = array('pub value', 3, 4);
public function __constructor($var)
{
$this->_var = $var;
}

public function show()
{
echo $this->_var;
}
}

$string = "It's a string...";
$array  = array(1, 2, 'key' => 'value', array('sub-array'));
$number = 135345.55;
$class  = new MyClass('class var');


//通过
serialize()方法我们可以将他们持久化比如:
echo serialize($string); //s:16:"It's a string...";
echo serialize($array);  //a:4:{i:0;i:1;i:1;i:2;s:3:"key";s:5:"value";i:2;a:1:{i:0;s:9:"sub-array";}}
echo serialize($number); //d:135345.5499999999883584678173065185546875;
echo serialize($class);  //O:7:"MyClass":2:{s:13:"MyClass_var";N;s:3:"pub";a:3:{i:0;s:9:"pub value";i:1;i:3;i:2;i:4;}}
// 我们可以将这些序列化的结果存到文件中,在需要的时候unserialize()返回得到相应的值,但是现在我不会这么做。

前篇文章提到了通过include返回值来直接取得php值对象,首先我们要把值保存起来,因为我们要通过include来包含它,首先遇到的问题就是我们的序列化函数必须要生成合法的php表达式才行,否则include是无法得到相应的返回值的。
比如我们要序列化 字符串 "abcd" 我们可以这么做
file_puts_content("data.php", "return 'abcd';");
//然后这样取得相应的值
$string = include "data.php";
echo $string; // 它应该输出 abcd
那数组怎么办呢?比如上面的数组。
我们可以自己编写这个序列化函数

function encode($var){
if (is_array($var)) {
$code = 'array(';
foreach ($var as $key => $value) {
$code .= "'$key'=>".encode($value).',';
}
$code = chop($code, ','); //remove unnecessary coma
$code .= ')';
return $code;
} else {
if (is_string($var)) {
return "'".$var."'";
} elseif (is_bool($var)) {
return ($var ? 'TRUE' : 'FALSE');
} elseif (
is_numeric($var)) {
return "$var";
}
else
{
return 'NULL'
}
}
}
这个函数可以将字符串,数组以及数字变成合法的php表达式。
比如:
file_put_contents("data.php", "<?phpn return " . encode($array) . ";n");
data.php文件的结果是:
<?php
return array ( 0 => 1, 1 => 2, 'key' => 'value', 2 => array ( 0 => 'sub-array', ), )array(4) { [0]=> int(1) [1]=> int(2) ["key"]=> string(5) "value" [2]=> array(1) { [0]=> string(9) "sub-array" } } ;
我们的目的达到了。可以直接的通过include这个文件来得到我们的值。
但是现在有个问题,我们没有序列化对象类型的值,这个该怎么处理呢?
一个类对象有对象的状态和对象的行为,行为在类定义完以后就确定了,所以每个类的实例的行为都是一样的。所以我们可以不考虑,我们只需要考虑类对象的状态就可以了,简单来讲就是类的属性状态需要保存起来。那怎么样得到一个类的属性呢?
经过一番搜寻以后发现一个函数
get_object_vars
(PHP 4, PHP 5)

get_object_vars -- 返回由对象属性组成的关联数组

这个函数可以获得对象的属性关联数组,也就只可以得到对象的状态,但是对象的属性有各种访问控制,get_object_vars()函数在对象外访问只能得到对象的公开属性,而无法得到私有属性,这样的话我们就无法得到对象的全部状态,不可行,但是在对象内可以得到对象的所有属性,那我们可不可以在对象内定义一个___get_properties()方法来返回这些状态呢。
给类增加这样一个方法
public function __get_properties()
{
return get_obj_vars($this);
}
这样我们就可以得到类的所有属性了。第一步算是完成了,我们得到状态该怎么重新恢复出来呢?要在对象外部给对象设置属性我们只有两种情况:一种是这个属性是公开属性,我们可以直接赋值 比如: $obj->prop = $value; 如果是私有属性我们则需要自己增加setter方法比如 setProp($value);方法,来设置。但是这就会遇到一个问题,我们的属性要么是公开属性,要么必须要有setter方法来设置,很多情况下我们不希望给类增加这么多没有实际用处的方法,也为了封装性,不会有这么多的setter方法。虽然我们能得到对象的状态,但是却无法恢复对象状态,这样的话,我们的序列化方法也就没有什么意义了。我们探索到现在算是失败了。
解决办法:var_export()函数。
在看symfony代码的时候发现了这个函数,手册是这么描述的:
---------
var_export
(PHP 4 >= 4.2.0, PHP 5)

var_export -- 输出或返回一个变量的字符串表示
描述
mixed var_export ( mixed expression [, bool return] )

此函数返回关于传递给该函数的变量的结构信息,它和 var_dump() 类似,不同的是其返回的表示是合法的 PHP 代码。

您可以通过将函数的第二个参数设置为 TRUE,从而返回变量的表示。

------
这个就是我们想要的那个函数
我们来看看这个函数是怎么使用的。
//变量继续使用上面定义的变量
echo var_export($string);  //'It's a string...'
echo var_export($array);
/*
array (

0 => 1,  1 => 2,  'key' => 'value',  2 =>  array (    0 => 'sub-array',  ),)*/
echo var_export($number); // 135345.55
echo var_export($class);
/*

MyClass::__set_state(array(   '_var' => NULL,   'pub' =>  array (    0 => 'pub value',    1 => 3,    2 => 4,  ),))*/
我们可以看到生成的都是合法的PHP表达式。通过设置第二个参数为true,就可以将返回结果赋值给变量比如$new_array_string = var_export($array, TRUE);然后将这个结果写入文件持久化 file_put_contents("data.php", "<?php return $new_array_string;");像上面提到的那样,include就可以将值得到。细心的读者一定会注意第四个类实例对象var_export()返回的类静态函数的调用,同时传递了一个数组参数,他的键值就是该对象的属性和属性值。哦。。原来是这样的啊。原来有这样一个方法__set_state(), 这和__get() __set()方法一样都是magic方法。这个方法的作用就是用来设置对象状态的。这样就好办了。$got_class = include("data.php");$got_class->show();这时会报错,提示__set_state()方法不存在,因为var_export()方法是调用魔术方法__set_state(array());来恢复状态的。下一步我们要做的就是给类定义一个__set_state()方法,它接受一个数组。
class MyClass {
// 省略已有的代码
public public static function __set_state($var)
{
return new A();
}
}
这个函数必须要返回一个新的对象才行。虽然我没有让它通$var的值来这只状态,但是这个函数在我的php5.2.9下是不需要设置的。很神奇的就自动设置好了。最好的方式是:
public static function __set_state(array $array)
{
$tmp = new MyClass();
foreach($array as $key => $value)
{
$this->$key = $value;
}
}

我们可以给需要序列化的对象实现这个方法。或者建立一个 基类。让他们继承也可以。当然非对象类型是不需要实现这个函数的。
这样我们的序列化和反序列化都完成了,下面是完整的代码:
<?php
// @author Reeze <reeze.xia(at)gmail(dot)com>

// 缓存函数,将数值缓存到设置的文件中
function cache($file, $value)
{
$value_string = var_export($value, TRUE);
file_put_contents($file, "<?php return $value_string"); // 简单起见,不错异常检查
}
// 取出缓存的结果
function cache_get($file)
{
$value = include $file; // 这里也不做出错检查:比如文件是否存在,文件是否异常等。
return $value;
}

////////////////////////////////////////////////
// 测试缓存
////////////////////////////////////////////////
class MyClass
{
private $_var;
public  $pub  = array('pub value', 3, 4);
public function __constructor($var)
{
$this->_var = $var;
}

public function show()
{
echo $this->_var;
}
public static function __set_state(array $array)
{
$tmp = new MyClass();
foreach($array as $key => $value)
{
$this->$key = $value;
}
}
}

// 一些变量
$string = "It's a string...";
$array  = array(1, 2, 'key' => 'value', array('sub-array'));
$number = 135345.55;
$class  = new MyClass('class var')

// 缓存
cache("string.data.php", $string); // 当然扩展名不一定非得php, 文件名我也只是简单的处理
cache("array.data.php", $array);
// 等等。。。

// 获取数据,当然也可以在其他文件中来获取。
$class = cache_get("class.data.php");

参考:http://www.thoughtlabs.com/2008/02/02/phps-mystical-__set_state-method/?dsq=12016456
Posted in PHP, Web | Leave a comment

gmail新功能之标签改进

今天刚登陆gmail,又发现新的惊喜:

new

很久以前gmail就支持了给邮件加标签的功能,但是到后面基本没有用到,主要有两个原因: 加标签麻烦,以前标签的位置有点低,即使是拖到最上面还是很低,比较麻烦,二是因为以前给邮件加标签似乎只能通过菜单栏来加标签,现在可以直接通过拖放给邮件加标签,如下图:

label

现在标签的位置和收件箱紧靠着,同时可以把不常用的标签隐藏起来,标签可以重排序,gmail的beta是实实在在的beta,永远不满足,我喜欢:)

1

Posted in Web | Leave a comment

PHP中include()函数(以及相关函数)的返回值及避免序列化开销的方法

以前乱翻symfony生成的缓存文件的时候看到很多类似:


<?php return array('key' => "value"....); ?>

这种表达式,当时并没有怎么在意,今天研究symfony代码的时候看到这样一句代码


<?php  $this->classes = include($file); ?>

一直都是通过include require来包含文件,但是从来没有使用过他的返回值,印象中include返回的无非是true &false吧。今天自己看了下文档,发现在php文件中是可以直接调用return的。比如

// return.php

<?php

$value = array('haha', 1, 3);

return $value;

?>

// get_return.php

<?php

$value = include("return.php");

echo $value; // 输出 Array, 因为$value 是从return.php返回的一个数组

?>

其实项目中很少情况需要这样的返回方法。如果想要从return.php中得到返回值一般是通过调用return.php中所调用的函数来得到。

在symfony中这种方式就很合理,如果大家熟悉symfony的话,应该知道,symfony运行起来以后会在cache目录下生成系统配置文件的缓存 ,诚然可以通过序列化的方式来缓存这些信息,但是反序列化是需要消耗资源的。通过这种方式来做持久化也是个不错的选择.

Posted in PHP | Leave a comment

PHP5.2.6中无法在exception_handler函数中抛出异常

在PHP bugs列表中也找到这个bug,但是似乎没有被处理,bug提出的时间是2005年,不知道新版本的有没有解决。
PHP:5.2.6
OS: Mac OS Leopard 10.5.7
Server: Apache 2.2

这个代码就有问题:
function e_handler($e)
{
throw new Exception();
}
set_exception_handler('e_handler');
throw new Exception();

这将会导致
Fatal error: Exception thrown without a stack frame in Unknown on line 0

Update: 这应该属于设计问题,如果在exception_handler()函数中可以跑出异常,则这个异常优惠调用exception_handler(),这样下去就会出现死循环,这就是为什么程序会出错的原因吧。
通过try catch来处理的话就没有问题。。

function e_handler($e)
{
try
{
throw new Exception();
}
catch (Exception $e)
{
echo "catched...";
}
}
set_exception_handler('e_handler');

throw new Exception();

Posted in PHP | Leave a comment

Mac下我常用的软件

习惯了Mac OS X Leopard以后发现自己已经离不开它了。像很多Linuxer一样除了上网银以外统统不用Windows,玩个CS什么的也都用Wine了,我很笨,目前在Mac 上和Ubuntu下都没有Wine成功过 :( ``, 下面就介绍一些我认为在Mac下非常使用的软件吧。
1. QuickSilver

只需要Command+Space 再加上几个字母就可以方便的你的程序,通过一些插件QuickSilver能极大的提高我们的效率,强烈推荐,唯一不足的是这款软件的作者已经不继续维护这款软件了,他被Google请去做另外一款和这个类似的软件Google Quick Search Box 试用了一下还不够成熟,目前和QS比起来还是差太多了。

2. TextMate

这款软件就不用多介绍了吧,强大的编辑器。开发进度有点慢,作者对软件质量要求很高,不许诺2.0版本到底何时能出来,很多人都以为作者停止了开发,前不久作者发布了这篇文章,声明开发仍在继续,感兴趣的同学可以看这里看看TextMate2.0到底有哪些改进。这篇在2007年就发布了。实在过的有点久了。

3.Things

GTD绝佳软件,缺点不具有网络同步功能

4.Evernote

笔记软件,很方便,之前我也用Evernote来做GTD发现管理器来很不方便,后来发现上面提到的Things就放弃用Evernote做GTD了,Evernote做笔记绝对顺手,他同时提供Windows 和Mac OS 两个版本,还有Web版的,跨平台很有优势。免费用户提供40M得空间,对我来说这其实绝对够用。

5.Adium

多协议IM客户端支持:Gtalk, MSN, ...QQ(因为QQ的协议是不公开的,所以可能定期会抽风,上QQ也可以用官方的 QQ for Mac)..

6.Tweetie

Twitter就靠他了,说不出那里好,就是很好用。免费版有广告。还好基本不影响用户体验。

7.iChm

看chm的电子书就靠它了。支持搜索

8.RescueTime

这个软件也有各个操作系统的版本,收集自己的时间分配,然后会有个汇总。

9.AppZapper

卸载软件用它来卸载还是比较干净的。方便快捷

10.Monolingual

帮你清除一些不需要的语言信息,节省磁盘空间。

Posted in Mac | Leave a comment

Mac OS 启动sshd服务

想push自己写的一些代码到本地的版本库中去,看了很多的协议,都挺麻烦的,至今没有配置好一个git server,遂放弃搭建server,直接使用ssh来提交到本地

无奈Mac OS X 似乎默认不启动SSHD服务。所以我尝试启动

Leopard:etc reeze$ sshd
sshd re-exec requires execution with an absolute path
看来不行。
不过这个提示错误似乎不是很明白。上网baidu了一把。发现
只能用绝对路径启动。不知道为什么程序非得用绝对路劲启动。有时间研究下为何是这样的,或者有知道的直接告诉我:)
$ sudo /usr/sbin/sshd
服务就启动了
不能每次都这么运行一下先啊。放在 ~/.bashrc 似乎可以,不过这个得需要管理员权限
得sudo,每次输入密码很烦人。干脆放到 /etc/rc.common,

#####
/usr/sbin/sshd

网上有人说apple不推荐这么干。但是我又不知道怎么让他自动启动。先就这么放着吧。找到好方法再改。

Posted in Mac | Tagged | Leave a comment

PHP调试函数

在项目中经常要调试程序,但是我电脑上的ZendStudio总是没配置好,不能单步调试,不过有时候不一定需要让ZendStudio来帮我们调试,所以写了下面这个辅助函数来方便调试,因为有时候调试的位置加多了自己也不知道到底是加在什么地方了,下面的函数就是方便的dump对象信息,同时显示调试的问题和所在的行数。

//调试函数,方便显示调试函数的位置和文件
function p(){

$args = func_get_args();
$backtrace = debug_backtrace(); // 调用栈

$file = $backtrace[0]['file'];
$line = $backtrace[0]['line'];
echo "<pre>";
echo "$file:$line\n";
foreach ($args as $arg)
{
var_dump($arg);
}
echo "</pre>";
exit;
}
debug_backtrace()可以返回调用栈。这样 我们就可以方便的知道函数在哪里条用的。

Posted in PHP | Tagged , | Leave a comment