<?php
/**
* author: selfimpr
* mail: lgg860911@yahoo.com.cn
* blog: http://blog.csdn.net/lgg201
* 下面提到的代码在PHP5.3以上版本运行通过.
*/
function callback($callback) {
$callback();
}
//输出: This is a anonymous function.<br />\n
//这里是直接定义一个匿名函数进行传递, 在以往的版本中, 这是不可用的.
//现在, 这种语法非常舒服, 和javascript语法基本一致, 之所以说基本呢, 需要继续向下看
//结论: 一个舒服的语法必然会受欢迎的.
callback(function() {
print "This is a anonymous function.<br />\n";
});
//输出: This is a closure use string value, msg is: Hello, everyone.<br />\n
//这里首先定义了一个闭包, 这次户口本上有名字了...
//use, 一个新鲜的家伙...
//众所周知, 闭包: 内部函数使用了外部函数中定义的变量.
//在PHP新开放的闭包语法中, 我们就是用use来使用闭包外部定义的变量的.
//这里我们使用了外部变量$msg, 定义完之后, 又对其值进行了改变, 闭包被执行后输出的是原始值
//结论: 以传值方式传递的基础类型参数, 闭包use的值在闭包创建是就确定了.
$msg = "Hello, everyone";
$callback = function () use ($msg) {
print "This is a closure use string value, msg is: $msg. <br />\n";
};
$msg = "Hello, everybody";
callback($callback);
//输出: This is a closure use string value lazy bind, msg is: Hello, everybody.<br />\n
//换一种引用方式, 我们使用引用的方式来use
//可以发现这次输出是闭包定义后的值...
//这个其实不难理解, 我们以引用方式use, 那闭包use的是$msg这个变量的地址
//当后面对$msg这个地址上的值进行了改变之后, 闭包内再输出这个地址的值时, 自然改变了.
$msg = "Hello, everyone";
$callback = function () use (&$msg) {
print "This is a closure use string value lazy bind, msg is: $msg. <br />\n";
};
$msg = "Hello, everybody";
callback($callback);
//输出: This is a closure use object, msg is: Hello, everyone.<br />\n
//闭包中输出的是之前被拷贝的值为Hello, everyone的对象, 后面是对$obj这个名字的一个重新赋值.
//可以这样考虑
//1\. obj是对象Hello, everyone的名字
//2\. 对象Hello, everyone被闭包use, 闭包产生了一个对Hello, everyone对象的引用
//3\. obj被修改为Hello, everybody这个对象的名字
//4\. 注意, 是名字obj代表的实体变了, 而不是Hello, everyone对象, 那自然闭包的输出还是前面的Hello, everyone
$obj = (object) "Hello, everyone";
$callback = function () use ($obj) {
print "This is a closure use object, msg is: {$obj->scalar}. <br />\n";
};
$obj = (object) "Hello, everybody";
callback($callback);
//输出: This is a closure use object, msg is: Hello, everybody.<br />\n
//还是按照上面的步骤, 按部就班的来吧:
//1\. obj名字指向Hello, everyone对象
//2\. 闭包产生一个引用指向Hello, everyone对象
//3\. 修改obj名字指向的对象(即Hello, everyone对象)的scalar值
//4\. 执行闭包, 输出的自然是Hello, everybody, 因为其实只有一个真正的对象
$obj = (object) "Hello, everyone";
$callback = function () use ($obj) {
print "This is a closure use object, msg is: {$obj->scalar}. <br />\n";
};
$obj->scalar = "Hello, everybody";
callback($callback);
//输出: This is a closure use object lazy bind, msg is: Hello, everybody.<br />\n
//闭包引用的是什么呢? &$obj, 闭包产生的引用指向$obj这个名字所指向的地址.
//因此, 无论obj怎么变化, 都是逃不脱的....
//所以, 输出的就是改变后的值
$obj = (object) "Hello, everyone";
$counter_test = counter();
$callback = function () use (&$obj,&$counter_test) {
print "This is a closure use object lazy bind, msg is: {$obj->scalar}. ".$counter_test()."<br />\n";
};
$obj = (object) "Hello, everybody";
callback($callback);
/**
* 一个利用闭包的计数器产生器
* 这里其实借鉴的是python中介绍闭包时的例子...
* 我们可以这样考虑:
* 1\. counter函数每次调用, 创建一个局部变量$counter, 初始化为1.
* 2\. 然后创建一个闭包, 闭包产生了对局部变量$counter的引用.
* 3\. 函数counter返回创建的闭包, 并销毁局部变量, 但此时有闭包对$counter的引用,
* 它并不会被回收, 因此, 我们可以这样理解, 被函数counter返回的闭包, 携带了一个游离态的
* 变量.
* 4\. 由于每次调用counter都会创建独立的$counter和闭包, 因此返回的闭包相互之间是独立的.
* 5\. 执行被返回的闭包, 对其携带的游离态变量自增并返回, 得到的就是一个计数器.
* 结论: 此函数可以用来生成相互独立的计数器.
*/
function counter() {
$counter = 1;
return function() use(&$counter) {return $counter ++;};
}
$counter1 = counter();
$counter2 = counter();
echo "counter1: " . $counter1() . "<br />\n";
echo "counter1: " . $counter1() . "<br />\n";
echo "counter1: " . $counter1() . "<br />\n";
echo "counter1: " . $counter1() . "<br />\n";
echo "counter2: " . $counter2() . "<br />\n";
echo "counter2: " . $counter2() . "<br />\n";
echo "counter2: " . $counter2() . "<br />\n";
echo "counter2: " . $counter2() . "<br />\n";
?>
PHP Trait
自PHP5.4.0是PHP实现代码重用称为性状的方法。
性状是单继承的语言,如PHP的机制,代码重用。性状的目的是通过使开发人员能够在几个独立的类生活在不同的类层次重用套自由的方法来降低单继承的一些限制。性状和类组合的语义方式,也降低了复杂性定义,并避免与多重继承和混入相关的典型问题。
一个特点是相似的一类,但只用于组功能的细粒度和一致的方式。这是不可能实例化一个性状本身。这是一个除了传统的继承,使行为的横构图;也就是说,类成员的应用程序,而不需要继承。
Example #1 Trait example
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
**优先权 **
从基类继承的成员是由一个Trait插入成员覆盖。优先顺序是,从当前类重写Trait的方法,它的成员在返回重写继承的方法。
Example #2 Precedence Order Example
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo ‘World!’;
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
以上例程会输出:
Hello World!
PHP 开启函数exif_read_data
当我在WAMPSERVER 集成环境中开启 php_exif 模块.; 读取图片exif 信息时出现:
Fatal error: Call to undefined function exif_read_data()
解决方法:打开 php.ini
把extension=php_exif.dll 这行移动extension=php_mbstring.dll后面.重起 所有服务即可.
不重新编译PHP为php增加openssl模块的方法
不重新编译PHP为php增加openssl模块的方法
yum -y install openssl
/usr/local/bin/是php的安装目录
切换到php安装目录的etx/openssl目录
cd /usr/local/src/php-5.2.8/ext/openssl /usr/local/bin/phpize
Cannot find config.m4.
Make sure that you run ‘/usr/local/bin/phpize’ in the top level source directory of the module
查看openssl目录下有个config.w32和config0.m4,把config0.m4改名为config.m4。
mv config0.m4 config.m4
执行:
/usr/local/bin/phpize
编译:
./configure --with-openssl --with-php-config=/usr/local/bin/php-config make;make install
提示成功后,在php.ini里加入extension = openssl.so
重启apache或php-fpm,完成.
PHP 开启错误提示
if( !ini_get('display_errors') ) {
ini_set('display_errors', 'On');
}
error_reporting(E_WARNING | E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING);
JS读取PHP中文COOKIE的乱码问题(兼容IE、火狐、...)
PHP设置COOKIE
<?php
$user_name = "我是好人";
$time=time() + 3600 * 24 * 30;
$user_name = mb_convert_encoding($user_name,"UTF-8","GBK");
setcookie('user_name', urlencode($user_name),$time, "/");
?>
JS读取COOKIE
<script language="javascript">
var user_name= decodeURI(getCookie("user_name"));
alert(user_name);
</script>
PHP无限级分类读取
get_child(0);
function get_child ($id=0) {
global $db;
$id = (int)$id ? (int)$id : 0;
$sql = "select `cat_id`,`cat_name` from `ecs_category` where `parent_id`='".$id."' ";//查询parent_id 的子类的分类
$resource = $db->query($sql);
echo '<ul>';
while ($result = $db->fetch_array($resource)) {
echo "<li>".$result['cat_id']."------".$result['cat_name']."</li>";//输出此类
get_child ( $result['cat_id']);//继续查询此类的下一子层
}
echo '</ul>';
}
PHP递归复制整个文件夹
<?php
/*
* 文件夹复制类,
* 赵春 2012年6月14日17:20:30
* 博客:www.zhaochun.net
*/
class CopyFile
{
public $fromFile;
public $toFile;
/*
* $fromFile 要复制谁
* $toFile 复制到那
*/
function copyFile($fromFile,$toFile){
$this->CreateFolder($toFile);
$folder1=opendir($fromFile);
while($f1=readdir($folder1)){
if($f1!="." && $f1!=".."){
$path2="{$fromFile}/{$f1}";
if(is_file($path2)){
$file = $path2;
$newfile = "{$toFile}/{$f1}";
copy($file, $newfile);
}elseif(is_dir($path2)){
$toFiles = $toFile.'/'.$f1;
$this->copyFile($path2,$toFiles);
}
}
}
}
/*
* 递归创建文件夹
*/
function CreateFolder($dir, $mode = 0777){
if (is_dir($dir) || @mkdir($dir,$mode)){
return true;
}
if (!$this->CreateFolder(dirname($dir),$mode)){
return false;
}
return @mkdir($dir, $mode);
}
}
//使用方法
//引入本类,直接new copyFile('要复制谁','复制到那');
//$file = new CopyFile('aaaa/aaaaa','bbbbb/bbbb');
?>
PHP 判断字符编码
function is_utf8($liehuo_net){
if (preg_match("/^([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}/",$liehuo_net) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}$/",$liehuo_net) == true || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){2,}/",$liehuo_net) == true){
return true;
}else{
return false;
}
}
PHP 批量抓取内容 Http_MultiRequest
<?php
class Http_MultiRequest
{
//要并行抓取的url 列表
private $urls = array();
//curl 的选项
private $options;
//构造函数
function __construct($options = array())
{
$this->setOptions($options);
}
//设置url 列表
function setUrls($urls)
{
$this->urls = $urls;
return $this;
}
//设置选项
function setOptions($options)
{
$options[CURLOPT_RETURNTRANSFER] = 1;
if (isset($options['HTTP_POST']))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $options['HTTP_POST']);
unset($options['HTTP_POST']);
}
if (!isset($options[CURLOPT_USERAGENT]))
{
$options[CURLOPT_USERAGENT] = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)';
}
if (!isset($options[CURLOPT_FOLLOWLOCATION]))
{
$options[CURLOPT_FOLLOWLOCATION] = 1;
}
if (!isset($options[CURLOPT_HEADER]))
{
$options[CURLOPT_HEADER] = 0;
}
$this->options = $options;
}
//并行抓取所有的内容
function exec()
{
if(empty($this->urls) || !is_array($this->urls))
{
return false;
}
$curl = $data = array();
$mh = curl_multi_init();
foreach($this->urls as $k => $v)
{
$curl[$k] = $this->addHandle($mh, $v);
}
$this->execMulitHandle($mh);
foreach($this->urls as $k => $v)
{
$data[$k] = curl_multi_getcontent($curl[$k]);
curl_multi_remove_handle($mh, $curl[$k]);
}
curl_multi_close($mh);
return $data;
}
//只抓取一个网页的内容。
function execOne($url)
{
if (empty($url)) {
return false;
}
$ch = curl_init($url);
$this->setOneOption($ch);
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
//内部函数,设置某个handle 的选项
private function setOneOption($ch)
{
curl_setopt_array($ch, $this->options);
}
//添加一个新的并行抓取 handle
private function addHandle($mh, $url)
{
$ch = curl_init($url);
$this->setOneOption($ch);
curl_multi_add_handle($mh, $ch);
return $ch;
}
//并行执行(这样的写法是一个常见的错误,我这里还是采用这样的写法,这个写法
//下载一个小文件都可能导致cup占用100%, 并且,这个循环会运行10万次以上
//这是一个典型的不懂原理产生的错误。这个错误在PHP官方的文档上都相当的常见。)
private function execMulitHandle($mh)
{
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running > 0);
}
}
/*下面是上面的类的一个测试的例子:*/
//$urls = array("http://www.baidu.com", "http://www.google.com", "http://www.sina.com.cn", "http://www.newsnow.com.cn/about/", "http://liulipeng01.blog.163.com");
$m = new Http_MultiRequest();
$urls = array("http://test3.99kt.com/index.php");
$t = microtime(true);
$m->setUrls($urls);
//parallel fetch(并行抓取):
$data = $m->exec();
$parallel_time = microtime(true) - $t;
echo $parallel_time . "\n";
$t = microtime(true);
//serial fetch(串行抓取):
$data = array();
foreach ($urls as $url)
{
$data[] = $m->execOne($url);
}
$serial_time = microtime(true) - $t;
echo $serial_time . "\n";
die;
?>