这里有新鲜出炉的 PHP 面向对象编程,程序狗速度看过来!
PHP(外文名: Hypertext Preprocessor,中文名:"超文本预处理器")是一种通用开源脚本语言。语法吸收了 C 语言、Java 和 Perl 的特点,入门门槛较低,易于学习,使用广泛,主要适用于 web 开发领域。PHP 的文件后缀名为 php。
多线程是 java 中一个很不错的东西,很多朋友说在 php 中不可以使用 PHP 多线程了,其实那是错误的说法,本文就是介绍 PHP 中多线程的两个实现方法,有兴趣的同学可以看一下。
PHP 本身是不是支持多线程的,不过我们可以借助其他的方法来实现多线程,比如 shell 服务,比如 web 服务器,本文我们来讲讲这两个方法如何实现。需要的朋友可以来参考一下。
多线程是 java 中一个很不错的东西,很多朋友说在 php 中不可以使用 PHP 多线程了,其实那是错误的说法 PHP 多线程实现方法和 fsockopen 函数有关,下面我们来介绍具体实现程序代码,有需要了解的同学可参考。
当有人想要实现并发功能时,他们通常会想到用 fork 或者 spawn threads,但是当他们发现 php 不支持多线程的时候,大概会转换思路去用一些不够好的语言,比如 perl。
其实的是大多数情况下,你大可不必使用 fork 或者线程,并且你会得到比用 fork 或 thread 更好的性能。
假设你要建立一个服务来检查正在运行的 n 台服务器,以确定他们还在正常运转。你可能会写下面这样的代码:
代码如下:
- <?php
- $hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
- $timeout = 15;
- $status = array();
- foreach ($hosts as $host) {
- $errno = 0;
- $errstr = "";
- $s = fsockopen($host, 80, $errno, $errstr, $timeout);
- if ($s) {
- $status[$host] = "Connectedn";
- fwrite($s, "HEAD / HTTP/1.0rnHost: $hostrnrn");
- do {
- $data = fread($s, 8192);
- if (strlen($data) == 0) {
- break;
- }
- $status[$host] .= $data;
- } while (true);
- fclose($s);
- } else {
- $status[$host] = "Connection failed: $errno $errstrn";
- }
- }
- print_r($status);
- ?>
它运行的很好,但是在 fsockopen() 分析完 hostname 并且建立一个成功的连接(或者延时 $timeout 秒)之前,扩充这段代码来管理大量服务器将耗费很长时间。
因此我们必须放弃这段代码;我们可以建立异步连接 - 不需要等待 fsockopen 返回连接状态。PHP 仍然需要解析 hostname(所以直接使用 ip 更加明智),不过将在打开一个连接之后立刻返回,继而我们就可以连接下一台服务器。
有两种方法可以实现;PHP5 中可以使用新增的 stream_socket_client() 函数直接替换掉 fsocketopen()。PHP5 之前的版本,你需要自己动手,用 sockets 扩展解决问题。
下面是 PHP5 中的解决方法:
它运行的很好,但是在 fsockopen() 分析完 hostname 并且建立一个成功的连接(或者延时 $timeout 秒)之前,扩充这段代码来管理大量服务器将耗费很长时间。
因此我们必须放弃这段代码;我们可以建立异步连接 - 不需要等待 fsockopen 返回连接状态。PHP 仍然需要解析 hostname(所以直接使用 ip 更加明智),不过将在打开一个连接之后立刻返回,继而我们就可以连接下一台服务器。
有两种方法可以实现;PHP5 中可以使用新增的 stream_socket_client() 函数直接替换掉 fsocketopen()。PHP5 之前的版本,你需要自己动手,用 sockets 扩展解决问题。
代码如下:
- <?php
- $hosts = array("host1.sample.com", "host2.sample.com", "host3.sample.com");
- $timeout = 15;
- $status = array();
- $sockets = array();
- /* Initiate connections to all the hosts simultaneously */
- foreach ($hosts as $id => $host) {
- $s = stream_socket_client("
- $
- $host:80", $errno, $errstr, $timeout,
- STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
- if ($s) {
- $sockets[$id] = $s;
- $status[$id] = "in progress";
- } else {
- $status[$id] = "failed, $errno $errstr";
- }
- }
- /* Now, wait for the results to come back in */
- while (count($sockets)) {
- $read = $write = $sockets;
- /* This is the magic function - explained below */
- $n = stream_select($read, $write, $e = null, $timeout);
- if ($n > 0) {
- /* readable sockets either have data for us, or are failed
- * connection attempts */
- foreach ($read as $r) {
- $id = array_search($r, $sockets);
- $data = fread($r, 8192);
- if (strlen($data) == 0) {
- if ($status[$id] == "in progress") {
- $status[$id] = "failed to connect";
- }
- fclose($r);
- unset($sockets[$id]);
- } else {
- $status[$id] .= $data;
- }
- }
- /* writeable sockets can accept an HTTP request */
- foreach ($write as $w) {
- $id = array_search($w, $sockets);
- fwrite($w, "HEAD / HTTP/1.0rnHost: "
- . $hosts[$id] . "rnrn");
- $status[$id] = "waiting for response";
- }
- } else {
- /* timed out waiting; assume that all hosts associated
- * with $sockets are faulty */
- foreach ($sockets as $id => $s) {
- $status[$id] = "timed out " . $status[$id];
- }
- break;
- }
- }
- foreach ($hosts as $id => $host) {
- echo "Host: $hostn";
- echo "Status: " . $status[$id] . "nn";
- }
- ?>
我们用 stream_select() 等待 sockets 打开的连接事件。stream_select() 调用系统的 select(2) 函数来工作:前面三个参数是你要使用的 streams 的数组;你可以对其读取,写入和获取异常(分别针对三个参数)。stream_select() 可以通过设置 $timeout(秒)参数来等待事件发生 - 事件发生时,相应的 sockets 数据将写入你传入的参数。
下面是 PHP4.1.0 之后版本的实现,如果你已经在编译 PHP 时包含了 sockets(ext/sockets) 支持,你可以使用根上面类似的代码,只是需要将上面的 streams/filesystem 函数的功能用 ext/sockets 函数实现。主要的不同在于我们用下面的函数代替 stream_socket_client() 来建立连接:
代码如下:
- <?php
- // This value is correct for Linux, other systems have other values
- define('EINPROGRESS', 115);
- function non_blocking_connect($host, $port, &$errno, &$errstr, $timeout) {
- $ip = gethostbyname($host);
- $s = socket_create(AF_INET, SOCK_STREAM, 0);
- if (socket_set_nonblock($s)) {
- $r = @socket_connect($s, $ip, $port);
- if ($r || socket_last_error() == EINPROGRESS) {
- $errno = EINPROGRESS;
- return $s;
- }
- }
- $errno = socket_last_error($s);
- $errstr = socket_strerror($errno);
- socket_close($s);
- return false;
- }
- ?>
现在用 socket_select() 替换掉 stream_select(),用 socket_read() 替换掉 fread(),用 socket_write() 替换掉 fwrite(),用 socket_close() 替换掉 fclose() 就可以执行脚本了!
PHP5 的先进之处在于,你可以用 stream_select() 处理几乎所有的 stream - 例如你可以通过 include STDIN 用它接收键盘输入并保存进数组,你还可以接收通过 proc_open() 打开的管道中的数据。
下面来分享一个 PHP 多线程类
代码如下:
- class thread {
- var $hooks = array();
- var $args = array();
- function thread() {
- }
- function addthread($func)
- {
- $args = array_slice(func_get_args(), 1);
- $this->hooks[] = $func;
- $this->args[] = $args;
- return true;
- }
- function runthread()
- {
- if(isset($_GET['flag']))
- {
- $flag = intval($_GET['flag']);
- }
- if($flag || $flag === 0)
- {
- call_user_func_array($this->hooks[$flag], $this->args[$flag]);
- }
- else
- {
- for($i = 0, $size = count($this->hooks); $i < $size; $i++)
- {
- $fp=fsockopen($_SERVER['HTTP_HOST'],$_SERVER['SERVER_PORT']);
- if($fp)
- {
- $out = "GET {$_SERVER['PHP_SELF']}?flag=$i HTTP/1.1rn";
- $out .= "Host: {$_SERVER['HTTP_HOST']}rn";
- $out .= "Connection: Closernrn";
- fputs($fp,$out);
- fclose($fp);
- }
- }
- }
- }
- }
来源: http://www.phperz.com/article/17/0806/342016.html