configure: error: Cannot locate header file libintl.h 错误的解决方法

MAC OS 上编译 PHP 时,在 configure 配置阶段出现如题所示错误。找不到 libintl.h 头文件。

解决方法如下:

1. 安装 gettext:

brew install gettext

2. 编辑 configure 文件:

将:

for i in $PHP_GETTEXT /usr/local /usr ; do

更改为:

for i in $PHP_GETTEXT /usr/local /usr /usr/local/opt/gettext; do

3. 重新运行 ./configure 即可

深入理解 PHP 之 count 函数

曾有一次面试时面试官问我

count('abc')

会返回多少。当时我一下子懵了,不带这样玩的啊,count 函数不是用来计算数组元素个数的么,你传个字符串进去是几个意思啊。然后我满脸疑问并不自信的回答,是 3 吗,因为我觉得 PHP 的字符串也有时候可以表现得像数组,比如你可以用下标来取到字符串中对应位置的字符。面试官说是 1,然后我说没这样用过,一般都是用 count 来计算数组元素个数,面试官说,这就说明你代码量不够了。

写了简单文件,我们来看看给 count 函数传入非数组的参数时会返回什么:

<?php

var_dump(count('abc'));
var_dump(count(''));
var_dump(count(0));
var_dump(count(false));
var_dump(count(null));

$books = array(
	array(
		'name' => 'Pairs',
		'price' => 30,
	),
	array(
		'name' => 'Apple',
		'price' => 20,
	),
);

var_dump(count($books));
var_dump(count($books, COUNT_RECURSIVE));

上面代码输出如下:

int(1)
int(1)
int(1)
int(1)
int(0)
int(2)
int(6)

可以看到 count 在作用于非数组的变量时,除了 null,其它都返回 1,为什么会这样呢,我们来看看 PHP 有关于 count 函数的 C 源代码:

/* {{{ proto int count(mixed var [, int mode])
   Count the number of elements in a variable (usually an array) */
PHP_FUNCTION(count)
{
	zval *array;
	long mode = COUNT_NORMAL;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
		return;
	}

	switch (Z_TYPE_P(array)) {
		case IS_NULL:
			RETURN_LONG(0);
			break;
		case IS_ARRAY:
			RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
			break;
		case IS_OBJECT: {
#ifdef HAVE_SPL
			zval *retval;
#endif
			/* first, we check if the handler is defined */
			if (Z_OBJ_HT_P(array)->count_elements) {
				RETVAL_LONG(1);
				if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
					return;
				}
			}
#ifdef HAVE_SPL
			/* if not and the object implements Countable we call its count() method */
			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
				zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
				if (retval) {
					convert_to_long_ex(&retval);
					RETVAL_LONG(Z_LVAL_P(retval));
					zval_ptr_dtor(&retval);
				}
				return;
			}
#endif
		}
		default:
			RETURN_LONG(1);
			break;
	}
}
/* }}} */

源码很明显,如果传入的参数为 null,则返回 0,如果传入的数组,则计算数组元素个数,如果是对象,则按对象进行相应处理(这个过程我不是太明白),重点在于最后的 default,也就是说其它任何类型都返回 1.

完。

各种语言对负数取模运算结果的对比

上次学 python 的时候发现负数的取模运算结果和 PHP 的不一样,于是今天就试了一下,对比下各编程语言的差异。代码如下(这里只给出 PHP 代码,完整的其它语言的代码请点这里):

#! /usr/bin/env php
<?php

printf("%d %d %d %d\n", 9 % 4, -9 % 4, 9 % -4, -9 % -4);
printf("%d %d %d %d\n", 8 % 4, -8 % 4, 8 % -4, -8 % -4);

上面的代码很简单,第一行是不能除尽的情况,第二行是可以除尽的情况。各种语言的输出结果如下:

c -----------------------------
1, -1, 1, -1
0, 0, 0, 0

java --------------------------
1 -1 1 -1
0 0 0 0

js ----------------------------
1 -1 1 -1
0 0 0 0

php ---------------------------
1 -1 1 -1
0 0 0 0

lua ---------------------------
1	3	-3	-1
0	0	0	0

perl --------------------------
1 3 -3 -1
0 0 0 0

python ------------------------
1 3 -3 -1
0 0 0 0

rb ----------------------------
1
3
-3
-1
0
0
0
0

sh ----------------------------
1 -1 -1 1
0 0 0 0

根据输出我们可以得到下面两个结论:

  1. 能被整除的情况下,各语言都是返回零。
  2. 不能整除的情况下,C style 风格的几种语言(c,java,js,php)输出的结果一致,另外几种语言(lua,perl,python,ruby)输出的结果一样,但与 C style 的结果不一样,shell 最特殊。

PHP 手册上面明确说明:取模运算符 % 的结果和被除数的符号(正负号)相同。即 $a % $b 的结果和 $a 的符号相同。计算规则是先按被除数和除数的绝对值进行计算,然后按规定相应地符号。

Python 取模的结果符号与除数一致。Python 取模运算两个操作数一正一负的情况下比 PHP 要复杂,具体怎么算的请看这里。Python2 的负数除法也有点奇怪啊,-26 / 20 的结果不是 -1 而是 -2,完全不符合直觉啊。Python3 里面 -26  / 20 的值是 -1.3。

PHP 中 array_replace 和 array_merge 区别

PHP 5.3.0 新增了一个函数 array_replace,和 array_merge 作用很相似。

先看下面代码示例:

<?php

$base = array(
	'name' => 'Lily',
	'age' => 20,
	'No index value',
);

$replace = array(
	'name' => 'Lucy',
	'addres' => 'Hubei',
	'No index value in array $replace',
);

print_r(array_merge($base, $replace));
print_r(array_replace($base, $replace));

上面代码输出为:

Array
(
    [name] => Lucy
    [age] => 20
    [0] => No index value
    [addres] => Hubei
    [1] => No index value in array $replace
)
Array
(
    [name] => Lucy
    [age] => 20
    [0] => No index value in array $replace
    [addres] => Hubei
)

很明显,array_replace 和 array_merge 的区别表现在处理数字索引的数据时,array_merge 会认为是不同的索引,不会进行覆盖,而 array_replace 则进行了覆盖。实际上 array_replace 和数组的 + 法运算的处理比较类似,但是参数的顺序得调换一下位置,下面的代码输出一致:

<?php

/* .....  数组定义同上 */

print_r(array_replace($base, $replace));
print_r($replace + $base);

 

没注意运算符优先级(漏掉括号)导致的一个 BUG

昨天新上线的一个项目,换了 $_SESSION 的处理方式。代码中有这样一条 SQL

$expiration = 1440 // <---- 这个在别的地方定义的
$sql = 'DELETE FROM session WHERE last_activity < ' . time() - $expiration;

线上代码运行过程不停的 warning ,说 SQL 语句执行出错,出错语句为 “-1440”,找了很长时间都没找到这个 BUG,后来终于找到那个 SQL  语句:

// 运行这一行语句,你会得到 -1400,而不是我们想要的 SQL 语句
echo 'DELETE FROM session WHERE last_activity < ' . time() - 1440;

为什么会是这样呢,因为字符串链接符 . 的优先级比运算符 – 要高,前面那一串先和 time() 返回的数字连成一个字符串,然后再与 1440 做减法运算,前面的一串字符串强制转换为数字 0,然后减 1440,就得到了 -1400,然后错误就出现啦。找到问题就好解决了,加上括号便 OK。

$expiration = 1440 // <---- 这个在别的地方定义的
$sql = 'DELETE FROM session WHERE last_activity < ' . (time() - $expiration);

话说这类错误很不好发现啊,项目里面那么多地方运行 SQL 查询,哪知道是哪里出错的呢。

看来有必要在 Log 里面里面记录函数调用栈,这样才能知道是哪里出错,能快速定位 BUG。

PHP CLI 模式输出彩色字符串

最近在写公司后台脚本程序代码。想到可以将不同的提示信息标注为不同的颜色,比如错误信息为红色,这样在监控输出地时候就可以将注意力集中在红色文字上。参考了别人的代码,做了一点小改动。如果有需要,请自取:(请注意,理论上该代码只能在 *nix 终端内能呈现彩色,Windows 不能用。)

ColorEcho: https://github.com/upliu/ColorEcho

MAC 上编译 PHP intl 扩展出现 Unable to detect ICU prefix or no failed 错误解决方法

进入扩展源码目录:

cd php-5.5.8/ext/intl

依次运行:

phpize
./configure

configure 这步会出错:

configure: error: Unable to detect ICU prefix or no failed. Please verify ICU install prefix and make sure icu-config works.

解决方法如下:

首先安装 icu4c:

brew install icu4c

然后:

./configure --with-icu-dir=/usr/local/opt/icu4c

接下来:

make && make install

大功告成!

Javascript 保留两位小数 保留多位小数

网上搜一番,发现很多手动算的文章,然后想起有 toFixed 方法就可以完成这个事情。我的疑问来了,不是有 toFixed 方法吗?干嘛要手动算,难道 IE6 不支持?我测试了一下,IE6 是支持的,直接 toFixed 就得了,还写函数干嘛?

var num = 123.456789;
alert(num.toFixed(2)); // 输出 123.46
alert(num.toFixed(3)); // 输出 123.457

alert(3.1415926.toFixed(2)); // 输出 3.14

// 下面是网上搜索到的函数
function formatFloat(src, pos)
{
    return Math.round(src*Math.pow(10, pos))/Math.pow(10, pos);
}

alert(formatFloat("1212.2323", 2));

我又想起 PHP 里面有需求是要获取微秒级别的时间戳,我们知道 time 是秒级的,PHP 里还有个函数是 microtime,这个函数默认返回字符串形式,要得到数字形式的怎么弄呢,网上还依然有很多博客(甚至时间为2012 2013年发布的文章,PHP5都出来10年了啊喂)在介绍下面这种老旧的方法:

function microtime_float(){ 
	list($usec, $sec) = explode(" ", microtime()); 
	return ((float)$usec + (float)$sec); 
}

但其实自 PHP 5.0 起 microtime 函数可以接受一个参数,如果为 true,则返回一个浮点数。

我相信,现在几乎没有不支持 PHP5 的环境了吧,microtime_float() 这类函数还有什么存在意义?

NetBeans Xdebug 调试老是等待链接

如果你确认你的 NetBeans 及 Xdebug 配置无误,但 NetBeans 就是显示等待链接,那么请接着往下看。

默认 NetBeans 的设置,PHP 调试器端口是 9000,默认 xdebug.remote_port 是 9000,这个配置是没有任何问题的。而 PHP-FPM 的默认监听端口也是 9000,所以,问题就是因为 9000 端口已经被 PHP-FPM 占用,NetBeans 链接 Xdebug 调试器端口显然就链接不上了。

解决办法:要么更改 xdebug.remote_port 和 NetBeans 的端口,要么更改 PHP-FPM 的监听端口(建议使用 Unix Sock)。

参考网址:http://www.cnblogs.com/azev/archive/2009/08/09/1542227.html

nginx + php-fpm 开启 PATH_INFO 模式

很多框架默认路由都是 PATH_INFO 模式,比如默认在 Apache 并且没有 rewrite 时,CodeIgniter 一般可以这样访问 /index.php/controller/action ,那么 nginx 和 php-fpm 如何设置支持 PATH_INFO 模式呢?

php.ini 中一个与 PATH_INFO 有关的设置是 cgi.fix_path 默认为 1,我们将其设置为 0。

php.ini 设置:

cgi.fix_path = 0

接下来是 nginx 配置:

location ~ \.php($|/) {
# 下面这一行设置 $fastcgi_script_name 和 $fastcgi_path_info 的值,具体请看 nginx 文档
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
# 下面这行也可以为 fastcgi_pass unix:/var/run/php-fpm.sock 看你的 fpm 设置了
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    include        fastcgi_params;
# 下面这行不能少默认 fastcgi_params 里面并没有 SCRIPT_FILENAME 
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO          $fastcgi_path_info;
}

看官如有疑问,请在下面留言,希望对您有帮助。

相关链接: