存档

文章标签 ‘php’

php中数组与字符串

2011年3月16日 20 条评论

因为php的语法要求不严格,字符串也可以当数组使用,这样就存在一个问题:当使用非数字作为key访问字符串中的内容时,就可能会带来一些不一致的情况,如下面的代码

$hello = "hello";
var_dump($hello['abc']);
var_dump($hello['0']);
var_dump($hello['1abc']);
var_dump($hello['12abc']);

输出的结果就不说了,简单运行一下就可以知道,我想原因是由intval这个东东引起的,时间关系,没有去确认zend的代码,不过下面代码的运行结果页说明了一些问题

var_dump(intval('abc'));
var_dump(intval('0'));
var_dump(intval('1abc'));
var_dump(intval('12abc'));

这个东东,对code review或者测试时候是一个很有杀伤力的bug,如果一个函数设计的返回值不好,有时候返回数组,有时候返回字符串,在使用之前,就一定要先判断返回结果是否为数组,否则就会在这个bug上杯具

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2011/03/16/php-array-with-string.html
---------------------------------------------------------------

分类: 程序员 标签: ,

sql运行简单封装

2010年7月23日 1 条评论

作为一个QA,我本来是很少写代码的,不过这段代码用的次数比较多,每次用的时候都改一些,比较烦,所以整理了一个通用的,作为个人代码库的第一块石头吧
升级于2010-7-26,修复bug

class sql_runner{

	private static $_arr_self = array();

	private $_addr = false;
	private $_user = false;
	private $_passwd = false;
	private $_db_connection = false;

	static function get_instance($addr, $user, $passwd){
		$key = $addr.'#'.$user.'#'.$passwd;
		if(false === array_key_exists($key, self::$_arr_self)){
			sql_runner::$_arr_self[$key] = new sql_runner($addr, $user, $passwd);
		}

		return sql_runner::$_arr_self[$key];
	}

	private function __construct($addr, $user, $passwd){
		$this->_addr = $addr;
		$this->_user = $user;
		$this->_passwd = $passwd;
	}

	public function run_sql($sql){

		if(false === $this->_db_connection || !mysql_ping($this->_db_connection)){
			UB_LOG_DEBUG("connecting db $this->_addr, $this->_user");
			$this->_db_connection = mysql_connect($this->_addr, $this->_user, $this->_passwd);

			if(false === $this->_db_connection){
				UB_LOG_FATAL("connect db failed: ".mysql_error());
				return false;
			}else{
				mysql_set_charset('latin1', $this->_db_connection);
			}
		}

		$result = false;
		$result = mysql_query($sql, $this->_db_connection);
		if(false === $result){
			UB_LOG_FATAL("[$sql] execute failed:". mysql_error($this->_db_connection)."\n");
			return false;
		}

		$result_arr = array();
		if(is_resource($result)){
			while($row = mysql_fetch_assoc($result)){
				$result_arr[] = $row;
			}
			mysql_free_result($result);
		}

		UB_LOG_DEBUG("[$sql] execute succed, selected result:".print_r($result_arr, true));
		return $result_arr;
	}

}

/**for log functions*/
if(!function_exists('UB_LOG_DEBUG')){
	function UB_LOG_DEBUG($log){
		print($log);
	}
}
if(!function_exists('UB_LOG_FATAL')){
	function UB_LOG_FATAL($log){
		print($log);
	}
}

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/07/23/sql-to-run-a-simple-package.html
---------------------------------------------------------------

分类: 程序员 标签: ,

sigterm sigint sigkill 区别

2010年5月20日 6 条评论

我看网上应该有不少搜索这个区别的问题,但是回答的都不全面,其中sigterm与sigint尤其有一点区别比较重要,但大都没有提及,今天我就遇到了这个问题,纠结了20分钟才搞明白咋回事。

首先,对于说这几个信号都是终止程序运行的说法不太准确,因为程序收到信号后,如果不对信号处理,就会导致程序退出,但如果程序捕获信号进行处理,按照它的逻辑,它是不一定会退出的。

在这三个信号中,sigkill是不能被捕获的,程序收到这个信号后,一定会退出。这就是kill -9一定能保证将程序杀死的原因。

下面说一下sigterm与sigint的区别,其中有一点区别区别很多文章都没有提及,也是我写这篇blog的原因(如果人家都写了,我就不用写了呗)

信号 产生方式 对进程的影响
sigint 通过ctrl+c将会对当进程发送此信号 信号被当前进程树接收到,也就是说,不仅当前进程会收到信号,它的子进程也会收到
sigterm kill命令不加参数就是发送这个信号 只有当前进程收到信号,子进程不会收到。如果当前进程被kill了,那么它的子进程的父进程将会是init,也就是pid为1的进程

下面这两个代码片段就能够验证这种情况(注意使用pcntl的时候,一定要declare ticks,要不然会杯具的发现函数没有被调用,进程不退出,信号发过去没有作用。php手册竟然没有强调这一点):

文件:loadhelper.php

#为了pcntl能够截获信号
declare(ticks = 1);

$arr_processes = array();

function terminate($signo){
    echo "aaaaaaaaaaa\n";
}

pcntl_signal(SIGTERM, "terminate", true);
pcntl_signal(SIGINT, "terminate", true);

foreach($argv as $key => $operation){

    if(0 === $key){
        continue;
    }   

    $pipes = array();
    $process = proc_open($operation, array(), &$pipes);
    if(false === $process){
        exit(-1);
    }
    $arr_processes[] = $process;
}

while(true){
    sleep(100);
}

文件:child.php

declare(ticks=1);

pcntl_signal(SIGINT, "terminate");
pcntl_signal(SIGTERM, "terminate");

function terminate($signo){
    echo "test_child\n";
}

while(true){
    sleep(100);
}

使用命令php loadhelper.php “php test.php”可以启动这个测试。
1.输入ctrl+c发送sigint可以看到,父进程与子进程的terminate都得到了执行,都有输出,但父进程不会退出,因为子进程还没有退出
2.通过kill向父进程的pid发送sigterm,可以看到,只有父进程输出

遗留问题:

父进程(loadhelper)接受到一次信号后,如果在terminate函数中调用exit,它还是不能退出的,因为还有子进程没有退出。但是从此以后它就不能再接收信号了(子进程还是能够接收到sigint),可能是exit使进程进入了待回收状态,具体还 需要后续在分析一把。

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/20/sigterm-sigint-sigkill-difference.html
---------------------------------------------------------------

分类: 程序员 标签: ,

php中getopt的缺陷及修复

2010年5月17日 1 条评论

在这里,我不得不再一次感叹php语言库函数的山寨与不专业。getopt函数就是一个典型的例子,通常用的时候,大家可能觉得没有什么,但在某些情况 下,就真的让人很囧。一个简单的函数,稍微多花几分钟就弄得更好一些了,但这个语言有个随意的开端,就有个随意的实现啊。

在linux中,使用getopt时候,有两种情况:

1.取得的参数解析成字符串:“php test_arg.php -c abc”,这种情况c参数取得的结果就是abc这个字符串

2.取得的参数解析成数组:“php test_arg.php -c abc -c abc123”,这种情况c参数取得的结果就是包含abc与abc123的数组

但是遇到这种情况呢:“php test_arg.php -c abc*”?由于linux的shell已经帮程序做了输入参数的解析,这时候c参数得到的既不是abc*这个结果也不是一个数组,而是被shell展开成了很多文件名后的第一个。

可能getopt用的童鞋很少,但这种山寨的设计,实在太让人憋屈了,自己花个10分钟写一个就比它的要好,为了避免大家重复劳动,分享一个代码片段

   function mygetopt(){
        global $argv;
        $result = array();

        $current_key = false;
        foreach($argv as $opt){

            $matches = array();
            if(1 === preg_match("/^-{1,2}(.*)$/", $opt, $matches)){
                $current_key = $matches[1];

                if(false === isset($result[$current_key])){
                    $result[$current_key] = false;
                }
            }else if (false !== $current_key){

                if(false === $result[$current_key]){
                    $result[$current_key] = $opt;
                }else{
                    if(false === is_array($result[$current_key])){
                        $result[$current_key] = array($result[$current_key]);
                    }
                    $result[$current_key][] = $opt;
                }
            }
        }   

        return $result;
    }

为了方便使用,将新版本的getopt函数设置为不接受任何参数,但是解析的结果可以输出所有的参数内容。因为php官方的getopt函数使用后,也无非是对输出的数组进行foreach之后进行switch,还不如方便点,直接解析所有呢。除了这一点,这个getopt函数的输出结果与php官方的完全一致

php官方getopt函数参考文档:http://cn.php.net/manual/en/function.getopt.php

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/17/php-and-repair-defects-in-the-getopt.html
---------------------------------------------------------------

分类: 程序员 标签: , ,

php中&符号的滥用与它引发的bug

2010年5月7日 1 条评论

php中,使用&表明这个引用是指针,这样在两个引用可以指向同一个内存空间。但其实不使用&的情况下,php也是写时拷贝的,zend引擎只有在修改的时候才会发生内存拷贝,不修改的话是不会产生消耗的。在实际使用中,我还发现使用&符号反而性能会降低。

在不需要修改的情况下,建议尽量不要使用&符号,否则不仅降低效率,还有可能造成出现bug。今天查看最近对测试框架的升级,就踩上了simpletest上面的一个bug,请看simpletest中,想testsuit加上case的函数:

function addTestCase(&$test_case) {
     $this->_test_cases[] = &$test_case;
}

这么简单的函数,我想大家一般都会认为没有问题吧,正常情况下它都能很好的工作,但是如果你这样用,就bug了:

foreach($arr_cases as $case){
     $this->test_suit->addTestCaseOpenTest($case);
}

你会发现_test_cases这个数组里面,只哟foreach最终的那个元素,因为函数都是接受的值引用,foreach改变$case的值,就把已经传入_test_cases数组的内容都给改写了,于是就悲剧了。对于simpletest来说,它并不需要修改用户的case程序,这样做值引用显然是多此一举,还产生了bug。

关于性能降低,用一个简单的代码测试一下就知道了

$a = array('a','c','n'); 

function printArray(&$arr)
{
    print(count($arr));
}

for($i=0;$i<100000;$i++){
    printArray($a);
}

用time命令跑一次,把printArray的&符号去掉再跑一次,可以看到大致下面的结果(机器不同,结果不同啊)

带有&符号 不带有&符号
real    0m0.183s
user    0m0.130s
sys     0m0.053s
real    0m0.160s
user    0m0.101s
sys     0m0.060s

可见使用&反而会使性能下降的,所以除非有必要,不建议使用&符号

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/05/07/php-in-the-ampersand-on-the-abuse-of.html
---------------------------------------------------------------

分类: 程序员 标签:

利用语言的动态特性减少switch

2010年4月21日 没有评论

以前也曾写过这样的代码,但没有特殊注意过,今天大家讨论收银台的问题时候,再提起这样的设计,却感觉非常有效。

因为分支很多,使用switch-case几乎是不可避免的,而这对与代码的维护与理解却不是一件很好的事情,在增加分支的时候,也是一种比较郁闷的事情。利用语言的动态特性与模块化的设计,可以在一定程度上减轻这种问题。

class A{};
class B{};

$arr_actions = array(
    'a' => 'A',
    'b' => 'B',
);

function do_action_no_switch($action){

    global $arr_actions;

    if(!array_key_exists($action, $arr_actions)){
        return false;
    }   

    $job = new $arr_actions[$action];

    //job->do...
}

do_action_no_switch('a');

---------------------------------------------------------------
本站作品根据创作共同协议进行授权, 转载时请务必以超链接形式标明文章原始出处
原文地址:http://www.mirecle.com/2010/04/21/reduce-the-use-of-the-dynamic-nature-of-language-switch.html
---------------------------------------------------------------

分类: 程序员 标签: