日志

PHP基于pcntl的多进程编程

PHP可以通过PHP的进程控制函数(PCNTL)实现多进程,要注意的是,PCNTL只在UNIX LIKE OS下有效,windows是不支持的,另外如果你在编译时没有加入这个扩展则需要自行安装.

pcntl_fork

首先我们需要了解一个非常重要的函数,pcntl_fork().

pcntl_fork —— 在当前进程当前位置产生分支(子进程).fork创建了一个子进程,父进程和子进程都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号(PID),而子进程得到的是0.通过fork创建的子进程可以看成是父进程的一个拷贝,无论是数据空间还是指令指针都完全一致,但从fork之后开始这两个父子进程就再也没有任何继承关系,两者可以看成是两个独立的进程,而fork返回值的差异可以作为父子进程的区分,也是多进程编程实现的关键.另外,如果fork失败,则会返回-1.

Talk is cheap show me the code:

#!/usr/bin/env php
<?php
date_default_timezone_set("asia/shanghai");

$pid = pcntl_fork();
if ($pid==-1) {
    die('fork失败');
} else if ($pid==0) {
    //子进程执行
    $sec = 10;
    echo date('H:i:s') .'| 我是子进程 (PID:' . posix_getpid() . ')' . ',我休眠' . $sec . '秒后结束' . PHP_EOL;
    
} else if ($pid>0) {
    //父进程执行
    $sec = 15;
    echo date('H:i:s') . '| 我是父进程 (PID:' . posix_getpid() . '),我创建了一个子进程 (PID:' . $pid . ')' . ',我休眠' . $sec . '秒后结束' . PHP_EOL;
}
sleep($sec);
echo date('H:i:s') . '| 进程(PID:'.posix_getpid().')结束' . PHP_EOL;
exit(0);

/**********************************输出*************************************
16:22:13| 我是父进程 (PID:28082),我创建了一个子进程 (PID:28083),我休眠15秒后结束
16:22:13| 我是子进程 (PID:28083),我休眠10秒后结束
16:22:23| 进程(PID:28083)结束
16:22:28| 进程(PID:28082)结束
****************************************************************************/

僵尸进程

阅读全文

日志

MAMP PRO 安装PHP扩展 以Memcache为例

1.编译memcache模块需要php的源码,根据php版本去官网下载php的源码,我的是php5.3.29

2.生成zend_config.h备用

cd php5.3.29

./configure

3.安装autoconf,已安装可以无视

curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.68.tar.bz2;

tar -xvf autoconf-2.68.tar.bz2

cd autoconf-2.68

./configure &amp;&amp; make

sudo make install

4.下载编译安装

curl -O http://pecl.php.net/get/memcache-2.2.4.tgz;

tar xf memcache-2.2.4.tgz;

cd memcache-2.2.4;

mkdir /Applications/MAMP/bin/php/php5.3.29/include/

# /Volumes/SOFT/php-5.3.29 是 php 的目录,根据实际自己改
ln -s /Volumes/SOFT/php-5.3.29 /Applications/MAMP/bin/php/php5.3.29/include/php

#建议 pwd 一下看看当前目录是不是memcache-2.2.4下,下面两行命令都必须要在这个目录下执行
/Applications/MAMP/bin/php/php5.3.29/bin/phpize;

./configure --with-php-config=/Applications/MAMP/bin/php/php5.3.29/bin/php-config

make

sudo make install

5.修改php.ini的配置

(!!!!不是到MAMP/bin/php/php.3.29/conf/php.ini下修改,这样是不会生效的,曾经被坑过!)
点 mamp 菜单,file->edit template -> php -> php 5.3.29 php.ini ,增加:

extension = memcache.so

MAMP会提示重启服务,yes就好了

安装结束

在页面输出一下PHPinfo(),command+f 搜索Memcache是否已经enable即可.

转载请注明出处:

© http://hejunhao.me

日志

PHP 基于 MySQL数据 导出 EXCEL文件

操作Excel可以使用第三方开源库,例如强大的:PHPEXCEL.

这里主要采用的是非第三方类库依赖,而是基于PHP5原生支持的fputcsv实现,基本可以满足日常需求.

<?php
// 输出Excel文件头 
header('Content-Type: application/vnd.ms-excel;charset=gbk');
header('Content-Disposition: attachment;filename="文件名.csv"');
header('Cache-Control: max-age=0');

// 从数据库中获取数据 
$sql = 'select * from `table` where ……';
$stmt = @mysql->query($sql);

// PHP文件句柄,php://output 表示直接输出到浏览器 
$fp = fopen('php://output', 'a');

// 输出Excel列头信息 
$head = array('姓名', '性别', '年龄', 'Email', '电话', '……');
foreach ($head as $i => $v) {
    // CSV的Excel支持GBK编码,一定要转换,否则乱码 
    $head[$i] = iconv('utf-8', 'gbk', $v);
}

// 写入列头 
fputcsv($fp, $head);

// 计数器 
$cnt = 0;
// 每隔$limit行,刷新一下输出buffer,节约资源 
$limit = 100000;

// 逐行取出数据,节约内存 
while ($row = $stmt->fetch(FETCH_NUM)) {

    $cnt ++;
    if ($limit == $cnt) { //刷新一下输出buffer,防止由于数据过多造成问题 
        ob_flush();
        flush();
        $cnt = 0;
    }

    foreach ($row as $i => $v) {
        $row[$i] = iconv('utf-8', 'gbk', $v);
    }
    fputcsv($fp, $row);
}
日志

PHP中使用cURL请求

cURL是一个非常强大的工具,它支持多种多样的协议(HTTP,FTP,TELNET等等)进行数据传输.因而cURL不受限于它能干什么,不管是基本的HTTP请求还是复杂的FTP上传或者是与需要验证处理的HTTPS网站进行交互,cURL都可以胜任。PHP通过cURL函数库对cURL提供了支持,下面主要介绍PHP cURL中使用最频繁的GET、POST方法和返回数据的处理,以及一些有用的cURL设置项。

  • 基本

在我们通过cURL请求进行各样操作之前,首先我们需要初始化一个cURL的实例对象,我们可以通过调用curl_init()这个方法来完成,它返回一个cURL的句柄。该方法提供一个可选参数,可以通过该参数设置要发送请求的URL地址,在此我们先不传参,下面会用另一种方式进行设置。

  • 设置

当我们拿到cURL的句柄后,我们就可以对其进行一系列的参数设定,下面是一些主要的设置项:

CURLOPT_RETURNTRANSFER

true:将返回的数据以文件流的形式返回;false:将返回的数据直接输出显示;

CURLOPT_CONNECTTIMEOUT

发起连接时等待的时间(秒);

CURLOPT_TIMEOUT

请求超时时间(秒);

CURLOPT_USERAGENT

设置请求的用户代理;

CURLOPT_URL

设置请求的URL地址

CURLOPT_POST

是否以POST方式发起请求

CURLOPT_POSTFIELDS

POST参数值

我们可以通过调用curl_setopt()方法设定指定的cURL参数值,该方法接收三个参数,分别是cURL句柄设置项(例如CURLOPT_URL)和设置值

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://hejunhao.me');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);

当我们需要设置大量参数时,显然重复使用大量curl_setopt并不方便,我们可以通过curl_setopt_array(),一次性设置大量参数。

<?php
$ch = curl_init();
$options = array(
    CURLOPT_URL => 'http://hejunhao.me',
    CURLOPT_HEADER => 0,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_NOPROGRESS => False,
    CURLOPT_TIMEOUT => 5
);
curl_setopt_array($ch, $options);
  • 发送请求

当我们设置好所有参数,准备发起请求时,我们通过调用curl_exec()方法来执行我们的请求,该方法接收一个cURL句柄参数。请求执行后会有三种可能的返回情况:
阅读全文

日志

Memcache 和 Memcached 的区别

很多人都无法分辨这两者的区别,甚至有人会认为Memcached是服务器的daemon进程
从手册中可以看到这两个扩展:memcache | memcached

显然,Memcached 比 Memcache 多了更多的实现,关于两者的区别可以简单理解如下:
1.Memcached 是基于 libmemcached 库的比 Memcache 实现了更多的协议(eg. Multigets and multisets allow you to get/set multiple items at the same time.)
2.Memcached 相比 Memcache 作了更多的优化
3.Memcached 支持 Binary Protocol,因此有更高的性能体现

日志

PHP类的访问控制

PHP的类属性、方法的可见性通过三个关键词来定义,即public、protected和private

  • 关键词

  1. public

    类成员(方法、属性)可以随处访问;
    以var声明的类属性会被定义为public性质;
    为了兼容PHP4,如果没有指定访问控制,属性和方法默认为公有的;

  2. protected

    类成员可以被自身、继承类和父类访问。(注意:类实例对象不可访问)

  3. private

    类成员只允许自身访问

  • 例子

PHP version: PHP5.5

<?php
class obj{
    public $obj_pub = 'obj_pub';
    protected $obj_protected = 'obj_protected';
    private $obj_private = 'obj_private';

    public function print_data(){
        echo $this->obj_private;
	echo $this->obj_protected;
	echo $this->obj_private;
    }

    protected function method_protected(){}

    private function method_private(){}
}

$o = new obj();
echo $o->obj_pub;//公有属性调用
echo $o->obj_protected; //报错,实例对象不可访问受保护的类属性
echo $o->obj_private; //报错,实例对象不可访问私有属性
echo $o->print_data();//调用公有方法

class animal extends obj{
    
    public function print_1(){
	echo $this->obj_pub;//调用父类公有属性
	echo $this->obj_protected;//调用父类受保护的属性
    }

    public function print_2(){
	echo $this->obj_privatje;//报错,父类私有属性禁止子类访问
    }

    public function foo(){
	$this->print_data();//调用父类公有方法
	$this->method_protected();//调用父类受保护的方法
	$this->method_private();//报错,父类私有方法禁止子类访问
    }
}

$a = new animal();
$a->print_1();
$a->print_2();
$a->foo();
转载请注明出处:

© http://hejunhao.me

日志

PHP的__construct和__destruct

__construct

__construct是PHP的构造函数,在对象创建时首先被调用,如果子类没有定义构造函数则会从父类继承其构造函数(非私有时),如果子类已经定义了构造函数则不会隐式调用父类的构造函数,子类可以通过parent::__construct(..)的方式调用父类构造函数.构造函数主要在对象创建时进行必要的初始化工作.

特别地,子类的构造函数的参数不需要与父类的构造函数一致,即覆盖时不会报E_STRICT错误

如果子类没有定义__construct(),也没有从父类继承,那么会尝试寻找旧式构造函数(与类同名的函数)(注意:从PHP5.3.3起,在命名空间中,与类同名的方法不再作为构造函数

__destruct

__destruct是PHP的析构函数,在对象被删除或隐式销毁时被调用. (since PHP5)

例子

<?php
class obj{
    public $name = '';
	
    function __construct($name){
	echo 'obj_construct call' . PHP_EOL;
	$this->name = $name;
    }

    function __toString(){
	return $this->name . PHP_EOL;
    }

    function __destruct(){
	echo 'obj_destruct call' . PHP_EOL;
    }
}

class animal extends obj{
    public $name = '';
    public $height = '';
	
    function __construct($name, $height){
	parent::__construct($name);
	echo 'animal_construct call' . PHP_EOL;
	$this->name = $name;
	$this->height = $height;
    }

    function __toString(){
	return $this->name . ': ' . $this->height . PHP_EOL;
    }
}

class dog extends animal{

    function __destruct(){
	echo 'dog_destruct call'.PHP_EOL;
    }
}

$d = new dog('dog','90cm');
echo $d;
unset($d);
echo '--------分割线-----' . PHP_EOL;
$a = new animal('animal', '100cm');
echo $a;
unset($a);

/********输出********

obj_construct call
animal_construct call
dog: 90cm
dog_destruct call
--------分割线-----
obj_construct call
animal_construct call
animal: 100cm
obj_destruct call

*********************/
日志

PHP中this、self和parent的区别

this

this是指向类实例化对象的指针,因此它指向的不是类而是类实例化后的对象,例如 $obj = new Animal(); 此时类内部定义的$this指的就是$obj这个对象,而不是Animal这个类.

self

self是类自身的引用,通常指向类的静态成员常量,在类体内引用静态成员和常量时不能用$this->var / $this->foo() 的形式.

parent

parent是指向父类的引用,通过parent可以访问父类方法(不管是否为静态)、父类静态成员父类常量,但不可以访问父类的非静态属性.(注意:$this也可以调用父类方法,但是如果继承类覆盖了父类方法A,那么$this->A()指的是继承类的A()方法,而parent::A()指的依然是父类的A()方法,不受覆盖影响

例子

<?php
class Object{
    public $name = '';
	
    public function __construct($name){
	$this->name = $name;
    }

    protected function foo(){
	echo 'Object foo function'.PHP_EOL;
    }
}

class Animal extends Object{
    public static $count = 0;
    const OBJECT_ID = 999;

    public function __construct($name){
	parent::__construct($name);
	self::count();
	parent::foo();
	$this->foo();
    }

    protected function foo(){
	echo 'Animal foo function'.PHP_EOL;
    }

    private static function count(){
	self::$count += 1;
    }
}

$a = new Animal('dog');
echo $a->name;
echo PHP_EOL;
echo Animal::$count;
echo PHP_EOL;
echo Animal::OBJECT_ID;
echo PHP_EOL;

$c = new Animal('cat');
echo $c->name;
echo PHP_EOL;
echo Animal::$count;
echo PHP_EOL;
echo Animal::OBJECT_ID;

/*****Output*****
 
Object foo function
Animal foo function
dog
1
999
Object foo function
Animal foo function
cat
2
999

*******************/
转载请注明出处:

© http://hejunhao.me