php memcache和php memcached比较以及问题

 更新时间:2016年11月25日 16:18  点击:2336
php memcache和php memcached是php的memcache分布式的高速缓存系统的两个客户端,php memcache是老客户端,php memcached是功能更加完善的新的代替php memcached的。

php memcache独立用php实现,是老客户端,从我们实践中已发现有多个问题,而且功能少,属性也可设置的少;
php memcached是基于原生的c的libmemcached的扩展,更加完善,建议替换为php memcached。

1. Php memcache的问题

1.1 分布式问题
php memcache默认会自动切换实例,所以有时取到老数据,并且value飘忽不定。
网友分享的问题:
这几天做某个产品的时候遇到一个小问题,现象比较诡异,产品用了两台分布式的memcached服务器。某一个计数器取回来的数偶尔会不对,最后定位在php memcache client的failover机制上面。
我们知道,在memcached分布式环境下,某一个key是通过hash计算,分配到某一个memcached上面的。
如果php.ini里面 memcache.allow_failover = 1的时候,在分布式环境下,某一台memcached出问题的话,会自动到其他的memcached尝试,就会出现上面的问题。所以要设置 allow_failover = 0 那么取不到时就直接返回失败而不会从其它mc上取,这样以避免网络异常或server端异常时,经常切换实例,会取到老数据。

1.2 高并发下稳定性问题
新浪微博提到的教训:
php memcache换成php memcached,在高并发下稳定下极大提高;
另外功能更多,出错码更精确。

Twitter的缓存经验
多层次Cache,减轻某些cache节点宕掉后的影响,读写都cache;
将memcached api统一换为libmemcached(方便多语言访问memcached,让分布式等各种规则都一致。)

1.3 1秒超时间隔没法修改问题
php memcache客户端有个1秒超时间隔没法修改问题:
bool Memcache::connect ( string $host [, int $port [, int $timeout ]] )
第三个参数本来可设置timeout,单位秒,但无法修改。
测试了以下三种修改timeout的方法都无效:
1.3.1. 用memcache api Memcache::setServerParams不能修改;
1.3.2. 改memcache 源代码vi php_memcache.h宏定义不能修改;
1.3.3. php.ini内这个配置:default_socket_timeout = 60对本timeout无效。

2. memcache和memcached对比

Php memcache这个老客户端在属性设置方面可设置的很少;
出错码粒度很粗,出错后难以定位;
而且功能欠缺一些:
There are primarily two clients used with PHP. One is the older, more widespread pecl/memcache and the other is the newer, less used, more feature rich pecl/memcached.
Both support the basics such as multiple servers, setting vaules, getting values, increment, decrement and getting stats.

Here are some more advanced features and information.
项目              pecl/memcache       pecl/memcached
First Release Date      2004-06-08      2009-01-29 (beta)
Actively Developed      Yes             Yes
External Dependency     None            libmemcached
Automatic Key Fixup1    Yes             No
Append/Prepend          No              Yes
Automatic Serialzation2 Yes             Yes
Binary Protocol         No              Optional
CAS                     No              Yes
Compression             Yes             Yes
Communication Timeout   Connect Only    Various Options
Consistent Hashing      Yes             Yes
Delayed Get             No              Yes
Multi-Get               Yes             Yes
Session Support         Yes             Yes
Set/Get to a specific server    No          Yes
Stores Numerics         Converted to Strings    Yes

注释:

1 pecl/memcache will convert an invalid key into a valid key for you. pecl/memcached will return false when trying to set/get a key that is not valid.
2 You do not have to serialize your objects or arrays before sending them to the set commands. Both clients will do

Open Flash Chart多报表我们在许多的网站都会看到这个功能了,今天小编就来为各位介绍Open Flash Chart多报表使用方法吧


将生成好的JSON数据传递给前端,前端通过JS来实现切换效果

例子。

<?php
//
// This is the MODEL section:
//
include '../php-ofc-library/open-flash-chart.php';
$title = new title( date("D M d Y") );
$bar = new bar();
$bar->set_values( array(9,8,7,6,5,4,3,2,1) );
$chart_1 = new open_flash_chart();
$chart_1->set_title( $title );
$chart_1->add_element( $bar );

// generate some random data
srand((double)microtime()*1000000);
$tmp = array();
for( $i=0; $i<9; $i++ )
  $tmp[] = rand(1,10);
$bar_2 = new bar();
$bar_2->set_values( $tmp );
$chart_2 = new open_flash_chart();
$chart_2->set_title( new title( "Chart 2 :-)" ) );
$chart_2->add_element( $bar_2 );

//
// This is the VIEW section:
//
?>
<html>
<head>
<script type="text/javascript" src="js/json/json2.js"></script>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("open-flash-chart.swf", "my_chart", "350", "200", "9.0.0");
</script>
<script type="text/javascript">
function ofc_ready()
{
    alert('ofc_ready');
}
function open_flash_chart_data()
{
    alert( 'reading data' );
    return JSON.stringify(data_1);
}
function load_1()
{
  tmp = findSWF("my_chart");
  x = tmp.load( JSON.stringify(data_1) );
}
function load_2()
{
  alert("loading data_2");
  tmp = findSWF("my_chart");
  x = tmp.load( JSON.stringify(data_2) );
}
function findSWF(movieName) {
  if (navigator.appName.indexOf("Microsoft")!= -1) {
    return window[movieName];
  } else {
    return document[movieName];
  }
}
    
var data_1 = <?php echo $chart_1->toPrettyString(); ?>;
var data_2 = <?php echo $chart_2->toPrettyString(); ?>;
</script>

</head>
<body>
<p>Open Flash Chart</p>

<div id="my_chart"></div>
<br>
<a href="javascript:load_1()">display data_1</a> || <a href="javascript:load_2()">display data_2</a>
<p>
Don't forget to 'view source' to see how the Javascript JSON data is loaded.
</p>
</body>
</html>

本文我们来分享关于Memcache查看列出所有key方法及利用memkeys实时查看memcached key使用情况,smemkeys是tumblr开源的类似top的工具,可用于实时查看memcached的key使用情况。

Memcache 查看列出所有key方法

今天在做一个Memcache的session测试,但是在测试的过程中,发现Memcache没有一个比较简单的方法可以直接象redis那样keys *列出所有的Session key,并根据key get对应的session内容,于是,我开始查找资料,翻出来的大部分是一些memcache常用命令等,但是对列出key的办法,讲解却不多,于是来到google,找到了一个国外的资料


具体的内容我套用我的测试环境中,操作如下

1. cmd上登录memcache

> telnet 127.0.0.1 11211

2. 列出所有keys

stats items // 这条是命令
STAT items:7:number 1
 STAT items:7:age 188
 END

3. 通过itemid获取key

接下来基于列出的items id,本例中为7,第2个参数为列出的长度,0为全部列出
stats cachedump 7 0 // 这条是命令
ITEM Sess_sidsvpc1473t1np08qnkvhf6j2 [183 b; 1394527347 s]
END

4. 通过get获取key值

上面的stats cachedump命令列出了我的session key,接下来就用get命令查找对应的session值
get Sess_sidsvpc1473t1np08qnkvhf6j2 //这条是命令
VALUE
Sess_sidsvpc1473t1np08qnkvhf6j2 1440 1
 83
 Sess_|a:5:{s:6:"verify";s:32:"e70981fd305170c41a5632b2a24bbcaa";s:3:"uid";s:1:"1
 ";s:8:"username";s:5:"admin";s:9:"logintime";s:19:"2014-03-11 16:24:25";s:7:"log
 inip";s:9:"127.0.0.1";}


memkeys实时查看memcached key使用情况

memkeys

memkeys是tumblr开源的类似top的工具,可用于实时查看memcached的key使用情况.

memkeys安装

安装autoconf(要求版本2.68以上):
# wget -c http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.gz
# tar zxvf autoconf-latest.tar.gz
# cd autoconf-2.69
# ./configure
# make && make install

安装其它依赖:
# yum install libpcap-devel pcre-devel ncurses-devel

安装memkeys:
# git clone https://github.com/tumblr/memkeys.git
# cd memkeys
# ./autogen.sh
# ./configure
# make && make install

memkeys使用

# memkeys -h
Usage: memkeys -i NIC [options]
    -d, --discard=THRESH        Discard keys where req/s rate is below THRESH
    -i, --interface=NIC         Network interface to capture traffic on (required)
    -p, --port=PORT             Network port to capture memcache traffic on (default 11211)
    -r, --refresh=INTERVAL      Refresh the stats display every INTERVAL ms (default 500)
    -l, --logfile=FILE          Output logs to FILE
    -R, --report=REPORT         Output data in REPORT format (CSV or curses, default curses)
 
    -h, --help                  This help
    -v, --verbose               Increase verbosity. May be used multiple times.
    -V, --version               Show program info and exit.

例子1:

# memkeys -i eth0 -l /tmp/memkeys.log

例子2:

# memkeys -i eth0 -d 10.0 -l /tmp/memkeys.log

ajax聊天室就是定时不定的刷新框架页面了,下面来给各位整理了一个PHP+mysql+ajax轻量级聊天室实例(兼容Chrome和IE)的例子,希望对大家有帮助.


做了一个QQ聊天交友网站,想加个聊天的功能,于是做完用PHP做了简单又强大的聊天室

1. 创建mysql数据库表:create table chat( id bigint AUTO_INCREMENT,username varchar(20), chatdate datetime,msg varchar(500), primary key(id));

2.编写建议连接数据库函数:

dbconnect.php

<?php


function db_connect()
{

  date_default_timezone_set("Asia/Shanghai");

  $link = mysql_connect("xxx.xxx.xxx.xxx", "databasename", "password")
            or die('无法连接: ' . mysql_error());
  mysql_select_db("databasename") or die('没有你找到指定数据库');
  return true;
}

 

function quote($strText)
{
    $Mstr = addslashes($strText);
    return "'" . $Mstr . "'";
}


function isdate($d)
{
   $ret = true;
   try
   {
       $x = date("d",$d);
   }
   catch (Exception $e)
   {
       $ret = false;
   }
   echo $x;
   return $ret;
}

 
?>
3. 编写ajax发送和接收函数:

ajax发送函数chat_send_ajax.php

<?php
     require_once('dbconnect.php');

     db_connect();

     $msg = iconv("UTF-8","GB2312",$_GET["msg"]);
     $dt = date("Y-m-d H:i:s");
     $user = iconv("UTF-8","GB2312",$_GET["name"]);

     $sql="INSERT INTO chat(USERNAME,CHATDATE,MSG) " .
          "values(" . quote($user) . "," . quote($dt) . "," . quote($msg) . ");";

          echo $sql;

     $result = mysql_query($sql);
     if(!$result)
     {
        throw new Exception('Query failed: ' . mysql_error());
        exit();
     }

?>

 


ajax接收函数chat_recv_ajax.php

<?php
header("Content-Type:text/html;charset=gb2312");
header("Expires: Thu, 01 Jan 1970 00:00:01 GMT");
   header("Cache-Control: no-cache, must-revalidate");
   header("Pragma: no-cache");
     require_once('dbconnect.php');

     db_connect();
    
     $sql = "SELECT *, date_format(chatdate,'%Y年%m月%d日 %r') as cdt from chat order by ID desc limit 200";
     $sql = "SELECT * FROM (" . $sql . ") as ch order by ID";
     $result = mysql_query($sql) or die('Query failed: ' . mysql_error());
    
     // Update Row Information
     $msg="<table border='0' style='font-size: 10pt; color: white; font-family: verdana, arial;'>";
     while ($line = mysql_fetch_array($result, MYSQL_ASSOC))
     {
           $msg = $msg . "<tr><td>" . $line["cdt"] . " </td>" .
                "<td>" . $line["username"] . ": </td>" .
                "<td>" . $line["msg"] . "</td></tr>";
     }
     $msg=$msg . "</table>";
    
     echo $msg;

?>

 


4.聊天室页面:

chat.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>聊天页面</title>
  
<script type="text/javascript">

var t = setInterval(function(){get_chat_msg()},5000);


//
// General Ajax Call
//
     
var oxmlHttp;
var oxmlHttpSend;
     
function get_chat_msg()
{

    if(typeof XMLHttpRequest != "undefined")
    {
        oxmlHttp = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    {
       oxmlHttp = new ActiveXObject("Microsoft.XMLHttp");
    }
    if(oxmlHttp == null)
    {
        alert("浏览器不支持XML Http Request!");
       return;
    }
   
    oxmlHttp.onreadystatechange = get_chat_msg_result;
    oxmlHttp.open("GET",encodeURI("chat_recv_ajax.php"),true);
    oxmlHttp.send(null);
}
    
function get_chat_msg_result()
{
    if(oxmlHttp.readyState==4 || oxmlHttp.readyState=="complete")
    {
        if (document.getElementById("DIV_CHAT") != null)
        {
            document.getElementById("DIV_CHAT").innerHTML =  oxmlHttp.responseText;
            oxmlHttp = null;
        }
        var scrollDiv = document.getElementById("DIV_CHAT");
        scrollDiv.scrollTop = scrollDiv.scrollHeight;
    }
}

     
function set_chat_msg()
{

    if(typeof XMLHttpRequest != "undefined")
    {
        oxmlHttpSend = new XMLHttpRequest();
    }
    else if (window.ActiveXObject)
    {
       oxmlHttpSend = new ActiveXObject("Microsoft.XMLHttp");
    }
    if(oxmlHttpSend == null)
    {
       alert("浏览器不支持XML Http Request!");
       return;
    }
   
    var url = "chat_send_ajax.php";
    var strname="noname";
    var strmsg="";
    if (document.getElementById("txtname") != null)
    {
        strname = document.getElementById("txtname").value;
        document.getElementById("txtname").readOnly=true;
    }
    if (document.getElementById("txtmsg") != null)
    {
        strmsg = document.getElementById("txtmsg").value;
        document.getElementById("txtmsg").value = "";
    }
   
    url += "?name=" + strname + "&msg=" + strmsg;
    oxmlHttpSend.open("GET",encodeURI(url),true);
    oxmlHttpSend.send(null);
}
function clickBtn(e)
  {
   if(window.event.keyCode==13)
   {
    var id=e.id;
    switch(id)
    {
     case "txtmsg":
      document.getElementById("Submit2").click();
      window.event.returnValue=false;
      break;
     }
   }
}
function fRandomBy(under, over){
switch(arguments.length){
case 1: return parseInt(Math.random()*under+1);
case 2: return parseInt(Math.random()*(over-under+1) + under);
default: return 0;
}
}
function SetTxtName(){
var i=fRandomBy(10);
if(i==0)document.getElementById('txtname').value='无敌战神';
if(i==1)document.getElementById('txtname').value='令狐冲';
if(i==2)document.getElementById('txtname').value='西门吹雪';
if(i==3)document.getElementById('txtname').value='超级玛丽';
if(i==4)document.getElementById('txtname').value='奥巴马';
if(i==5)document.getElementById('txtname').value='恐怖分子';
if(i==6)document.getElementById('txtname').value='聊斋奇女子';
if(i==7)document.getElementById('txtname').value='天朝?潘?;
if(i==8)document.getElementById('txtname').value='中500万了';
if(i==9)document.getElementById('txtname').value='神级奇葩';
if(i==10)document.getElementById('txtname').value='爱你不是两三天';
}
</script>

</head>
<body onload="SetTxtName();">
    
    <div style="border-right: black thin solid; border-top: black thin solid;
        border-left: black thin solid; border-bottom: black thin solid;
        background:#fff url('http://www.ihaonet.com/chat/blue.jpg') repeat-x left top;
        height: 450px;width: 500px; ">
        <table style="width:100%; height:100%">
            <tr>
                <td colspan="2" style="font-weight: bold; font-size: 16pt; color: white; font-family: verdana, arial;
                    text-align: center">
                    聊天窗口--全球最大QQ聊天交友网站</td>
            </tr>
            <tr>
                <td colspan="2" style="font-weight: bold; font-size: 16pt; color: white; font-family: verdana, arial;
                    text-align: left">
                    <table style="font-size: 12pt; color: white; font-family: Verdana, Arial;border: white thin solid; ">
                        <tr>
                            <td style="width: 100px">
                                名字:</td>
                            <td style="width: 100px"><input id="txtname" style="width: 150px" type="text" name="name" maxlength="15" value="匿名" /></td>
                        </tr>
                    </table>
                </td>
            </tr>
            <tr>
                <td style="vertical-align: middle;" valign="middle" colspan="2">
                    <div style="width: 480px; height: 300px; border-right: white thin solid; border-top: white thin solid; font-size: 10pt; border-left: white thin solid; border-bottom: white thin solid; font-family: verdana, arial; overflow:scroll; text-align: left;" id="DIV_CHAT">
                    </div>
                </td>
            </tr>
            <tr>
                <td style="width: 310px">
                    <input id="txtmsg" style="width: 350px" type="text" name="msg" onkeydown="return clickBtn(this)"/></td>
                <td style="width: 85px">
                    <input id="Submit2" style="font-family: verdana, arial" type="button" value="发送" onclick="set_chat_msg()"/></td>
            </tr>
            <tr>
                <td colspan="1" style="font-family: verdana, arial; text-align: center; width: 350px;">
                    </td>
                <td colspan="1" style="width: 85px; font-family: verdana, arial; text-align: center">
                </td>
            </tr>
        </table>
    </div>
</body>
</html>

 

效果:

 

php扩展开发对于很多朋友来讲都不太可能实现现因为php扩展开发是需要懂c的,下面我来为各位介绍一个 php扩展开发例子吧.

h1. 一、自动化建立扩展框架

到源码ext目录下

帮助
1
./ext_skel --extname=xiami_ext
生成如下几个文件文件列表:
* CREDITS
* EXPERIMENTAL
* config.m4
* config.w32
* php_xiami_ext.h
* tests
* xiami_ext.c
* xiami_ext.php

.c文件就是C语言系列的源文件,而.h文件则是C语言的头文件,即C系列中存放函数和全局变量的文件。子程序不要定义在*.h中。函数定义要放在*.c中,而*.h只做声明.否则多引用几次,就会发生函数重复定义的错误。

h1. 二、编写函数xiami_hello

h3. 1、不带参数

php_xiami_ext.h

 
PHP_MINIT_FUNCTION(xiami_ext);
PHP_MSHUTDOWN_FUNCTION(xiami_ext);
PHP_RINIT_FUNCTION(xiami_ext);
PHP_RSHUTDOWN_FUNCTION(xiami_ext);
PHP_MINFO_FUNCTION(xiami_ext);
 
PHP_FUNCTION(xiami_hello);
xiami_ext.c

 
const zend_function_entry xiami_ext_functions[] = {
    ZEND_FE(confirm_xiami_ext_compiled, NULL)
    ZEND_FE(xiami_hello,        NULL)
    PHP_FE_END
};
 
ZEND_FUNCTION(xiami_hello)
{
    php_printf("Hello World!n");
}
h3. 2、接收外来参数

xiami_ext.c
 
ZEND_BEGIN_ARG_INFO(arg_xiami_hello, 0)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
 
ZEND_FUNCTION(xiami_hello)
{
    char *name = NULL;
    int argc = ZEND_NUM_ARGS();
    int name_len;
 
    if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE)
        return;
    php_printf("hello %s",name);
}
 
const zend_function_entry xiami_ext_functions[] = {
    ZEND_FE(confirm_xiami_ext_compiled, NULL)
    ZEND_FE(xiami_hello,        arg_xiami_hello)
    PHP_FE_END
};
以ZEND_BEGIN_ARG_INFO宏定义开始,以ZEND_END_ARG_INFO()结束,这两个宏定义解释如下:

ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference):
开始参数块定义,pass_rest_by_reference为1时,强制所有参数为引用类型
ZEND_END_ARG_INFO()

ZEND_NUM_ARGS()代表着参数的个数:

 
参数   代表着的类型
b   Boolean
l   Integer 整型
d   Floating point 浮点型
s   String 字符串
r   Resource 资源
a   Array 数组
o   Object instance 对象
O   Object instance of a specified type 特定类型的对象
z   Non-specific zval 任意类型~
Z   zval**类型
h1. 三、编写类XiamiClass

h3. 1、步骤

# 创建一个全局的zend_class_entry变量,用于存储类的入口。
# 创建一个zend_function_entry结构体数组,用于存储类中包含的方法。
# 在扩展的MINIT方法中注册类。

h3. 2、空类

xiami_ext.c
首先,我们创建一个名为php_xiamiclass_entry的zend_class_entry结构体变量,该结构体变量实际存储了我们创建的类的入口。

 
zend_class_entry *php_xiamiclass_entry;
这里的php_xiamiclass_entry在扩展源文件中是一个全局变量,为了使其它扩展可以使用我们创建的类,
这个全局变量应该在头文件中定义。

接下来,我们创建zend_function_entry结构体数组,这个数组与函数定义时的数组是一样的。
 
const zend_function_entry xiami_ext_methods[] = {
    PHP_FE_END
};
在MINIT函数中,首先创建了一个xiami_ce变量用于存储临时的类入口,接下来使用INIT_CLASS_ENTRY
宏初始化该变量,之后使用zend_register_internal_class()将该类注册到Zend引擎,
该函数会返回一个最终的类入口,将其赋值给前面创建的全局变量。

 
PHP_MINIT_FUNCTION(xiami_ext)
{
    zend_class_entry xiami_ce;
    INIT_CLASS_ENTRY(xiami_ce, "XiamiClass", xiami_ext_methods);
 
    php_xiamiclass_entry = zend_register_internal_class(&xiami_ce TSRMLS_CC);
    return SUCCESS;
}
h3. 3、类方法

php_xiami_ext.h
 
PHP_MINIT_FUNCTION(xiami_ext);
PHP_MSHUTDOWN_FUNCTION(xiami_ext);
PHP_RINIT_FUNCTION(xiami_ext);
PHP_RSHUTDOWN_FUNCTION(xiami_ext);
PHP_MINFO_FUNCTION(xiami_ext);
 
PHP_METHOD(XiamiClass,__construct);
PHP_METHOD(XiamiClass, set_xiami_age);
xiami_ext.c
 
ZEND_BEGIN_ARG_INFO_EX(arg_construct, 0, 0, 1)
    ZEND_ARG_INFO(0, age)
ZEND_END_ARG_INFO();
 
ZEND_BEGIN_ARG_INFO(arg_xiami_age, 0)
    ZEND_ARG_INFO(0, age)
ZEND_END_ARG_INFO()
 
PHP_METHOD(XiamiClass, __construct)
{
    long age;
    if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &age) == FAILURE){
        WRONG_PARAM_COUNT;
    }
    if( age <= 0 ) {
        age = 1;
    }
 
    zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_age"), age TSRMLS_CC);
    RETURN_TRUE;
}
 
PHP_METHOD(XiamiClass, set_xiami_age)
{
    long age;
    if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &age) == FAILURE){
        WRONG_PARAM_COUNT;
    }
    if( age <= 0 ) {
        age = 1;
    }
    zend_update_property_long(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_age"), age TSRMLS_CC);
    RETURN_TRUE;
}
 
PHP_MINIT_FUNCTION(xiami_ext)
{
    zend_class_entry xiami_ce;
    INIT_CLASS_ENTRY(xiami_ce, "XiamiClass", xiami_ext_methods);
 
    php_xiamiclass_entry = zend_register_internal_class(&xiami_ce TSRMLS_CC);
 
    zend_declare_property_null(php_xiamiclass_entry, ZEND_STRL("_age"), ZEND_ACC_PRIVATE TSRMLS_CC);
    return SUCCESS;
}
zend_declare_property_*系列函数:

 
ZEND_API int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length, int access_type TSRMLS_DC);
用zend_read_property()和zend_update_property()函数:

 
ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, char *name, int name_length, zend_bool silent TSRMLS_DC);
 
ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, char *name, int name_length, zval *value TSRMLS_DC);
h1. 四、读取ini文件

php_xiami_ext.h

 
PHP_MINIT_FUNCTION(xiami_ext);
PHP_MSHUTDOWN_FUNCTION(xiami_ext);
PHP_RINIT_FUNCTION(xiami_ext);
PHP_RSHUTDOWN_FUNCTION(xiami_ext);
PHP_MINFO_FUNCTION(xiami_ext);
 
PHP_FUNCTION(xiami_hello);
ZEND_BEGIN_MODULE_GLOBALS(xiami_ext)
    long  age;
ZEND_END_MODULE_GLOBALS(xiami_ext)
 
#ifdef ZTS
#define XIAMI_EXT_G(v) TSRMG(xiami_ext_globals_id, zend_xiami_ext_globals *, v)
#else
#define XIAMI_EXT_G(v) (xiami_ext_globals.v)
#endif
xiami_ext.c

 
ZEND_DECLARE_MODULE_GLOBALS(xiami_ext)
 
PHP_INI_BEGIN()
   STD_PHP_INI_ENTRY("xiami_ext.age",      "42", PHP_INI_ALL, OnUpdateLong, age, zend_xiami_ext_globals, xiami_ext_globals)
PHP_INI_END()
 
static void php_xiami_ext_init_globals(zend_xiami_ext_globals *xiami_ext_globals)
{
    xiami_ext_globals->age = 10;
}
 
PHP_MINIT_FUNCTION(xiami_ext)
{
    ZEND_INIT_MODULE_GLOBALS(xiami_ext, php_xiami_ext_init_globals, NULL);
    REGISTER_INI_ENTRIES();
 
    return SUCCESS;
}
 
ZEND_FUNCTION(xiami_hello)
{
    RETURN_LONG(XIAMI_EXT_G(age));
}
 
const zend_function_entry xiami_ext_functions[] = {
    ZEND_FE(xiami_hello,        NULL)
    PHP_FE_END
};
STD_PHP_INI_ENTRY的最后三个参数是来告诉PHP修改哪个全局变量,我们扩展的全局变量的数据结构,以及这些全局变量被保存到的全局容器的名称。
在php_xiami_ext.h添加的内容中,使用了一对宏ZEND_BEGIN_MODULE_GLOBALS()和ZEND_END_MODULE_GLOBALS() — 用来创建一个包含一个age类型,名为zend_xiami_ext_globals的结构体。然后继续声明了XIAMI_EXT_G()来从一个线程池中获取值,或者只是从全局空间中获取 - 如果你为一个非线程环境编译的话。

在php_xiami_ext.c中你用了ZEND_DECLARE_MODULE_GLOBALS()宏来真正实例化zend_xiami_ext_globals结构体为一个真正的全局变量.最后,在MINIT中,你使用了ZEND_INIT_MODULE_GLOBALS()来分配一个线程安全的资源id.

phpinfo扩展信息中,显示ini信息

 
PHP_MINFO_FUNCTION(xiami_ext)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "xiami_ext support", "enabled");
    php_info_print_table_end();
 
    DISPLAY_INI_ENTRIES();
}
h1. 五、设置常量
 
PHP_MINIT_FUNCTION(ggg)
{
    zend_constant c;
    char *trim_key = "xiami";
    char *trim_val = "hello";
    int trim_val_len,trim_key_len;
 
    trim_key_len = strlen(trim_key);
    trim_val_len = strlen(trim_val);
 
    c.value.type = IS_STRING;
    c.value.value.str.val = pestrdup(trim_val, trim_val_len+1);
    c.value.value.str.len = trim_val_len;
    c.flags = CONST_PERSISTENT | CONST_CS;
    c.name = pestrdup(trim_key, trim_key_len+1);
    c.name_len = trim_key_len+1;
    c.module_number = module_number;
    zend_register_constant(&c TSRMLS_CC);
 
    return SUCCESS;
}
h1. 六、资源处理

PHP中的资源类型在内核中是通过一个zend_rsrc_list_entry结构体来实现:
 
typedef struct _zend_rsrc_list_entry {
    void *ptr;
    int type;
    int refcount;
} zend_rsrc_list_entry;
其中,ptr是一个指向资源的最终实现的指针,例如一个文件句柄,或者一个数据库连接结构。type是一个类型标记,用于区分不同的资源类型。refcount用于资源的引用计数。
资源类型可分为普通的资源,以及持久型的资源。例如mysql普通连接与持久连接。均保存在_zend_executor_globals结构体当中,其中包含如下两个HashTable
 
struct _zend_executor_globals {
    ...
    HashTable regular_list;
    HashTable persistent_list;
    ...
}
regular_list保存普通资源,persistent_list则保存持久型资源。
要使用资源,先要注册一个资源类型,使用如下的API函数:
 
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, const char *type_name, int module_number);
此函数返回一个资源类型id,zend_rsrc_list_entry结构体当中的type成员即对应此值。在扩展当中,此id应作为一个全局变量保存,以传递给其它资源API。
函数的第一及第二个参数,分别对应普通资源及持久资源的析构函数,第三个参数为资源类型的简短名称描述,一般用于错误提示,最后一个参数module_number为引擎内部使用,当我们调用这个函数时,只需要传递一个已经定义好的module_number变量。

 
static void myfile_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){
     FILE *fp = (FILE *) rsrc->ptr;
     fclose(fp);
}
 
PHP_MINIT_FUNCTION(myfile) {
 
//le_myfile是一个用于保存资源类型id的全局变量
     le_myfile = zend_register_list_destructors_ex(myfile_dtor,NULL,"standard-c-file", module_number);
     return SUCCESS;
要创建一个资源,通过ZEND_REGISTER_RESOURCE()函数:

 
ZEND_API int zend_register_resource(zval *rsrc_result, void *rsrc_pointer, int rsrc_type TSRMLS_DC);
#define ZEND_REGISTER_RESOURCE(rsrc_result, rsrc_pointer, rsrc_type)  zend_register_resource(rsrc_result, rsrc_pointer, rsrc_type TSRMLS_CC);
其第一个参数rsrc_result是一个指向zval的指针,很显然其作用是将PHP变量和资源进行绑定。
第二个参数rsrc_pointer是一个指向资源数据的指针。
第三个参数rsrc_type,很显然,是上面通过zend_register_list_destructors_ex()函数注册所返回的资源类型id。

 
PHP_FUNCTION(file_open){
     char *filename = NULL;
     char *mode = NULL;
     int argc = ZEND_NUM_ARGS();
     int filename_len;
     int mode_len;
     FILE *fp;
 
     if (zend_parse_parameters(argc TSRMLS_CC, "ss", &filename,&filename_len, &mode, &mode_len) == FAILURE) {
          return;
     }
 
     fp = fopen(filename, mode);
 
     if (fp == NULL) {
          RETURN_FALSE;
     }
 
     ZEND_REGISTER_RESOURCE(return_value, fp, le_myfile);
}
要访问一个资源,是通过ZEND_FETCH_RESOURCE()函数来进行的:

 
ZEND_API void *zend_fetch_resource(zval **passed_id TSRMLS_DC, int default_id, const char *resource_type_name, int *found_resource_type, int num_resource_types, ...);
#define ZEND_VERIFY_RESOURCE(rsrc)  if (!rsrc) { RETURN_FALSE; }
#define ZEND_FETCH_RESOURCE(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type)  rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC, default_id, resource_type_name, NULL, 1, resource_type);    ZEND_VERIFY_RESOURCE(rsrc);
第一个参数rsrc,是要保存资源值所对应的变量名。
第二个参数,是一个指针转换的定义,用于内部将资源转换为正确的类型。
第三个参数,是一个对应的资源值
第四个参数,用于实现资源的默认值
第五个参数,同zend_register_list_destructors_ex()的第三个参数
第六个参数,对应zend_register_list_destructors_ex()的返回值

 
PHP_FUNCTION(file_write){
     char *buffer = NULL;
     int argc = ZEND_NUM_ARGS();
     int buffer_len;
     zval *filehandle = NULL;
     FILE *fp;
 
     if (zend_parse_parameters(argc TSRMLS_CC, "rs", &filehandle,&buffer, &buffer_len) == FAILURE) {
          return;
     }
 
     ZEND_FETCH_RESOURCE(fp, FILE *, &filehandle, -1, "standard-cfile", le_myfile);
 
     if (fwrite(buffer, 1, buffer_len, fp) != buffer_len) {
          RETURN_FALSE;
     }
 
     RETURN_TRUE;
}
要删除一个资源,则使用zend_list_delete()函数:

 
ZEND_API int _zend_list_delete(int id TSRMLS_DC);
#define zend_list_delete(id)  _zend_list_delete(id TSRMLS_CC)
这个函数仅有一个资源id的参数,返回SUCCESS或者FAILURE。
 
 
PHP_FUNCTION(file_close){
     int argc = ZEND_NUM_ARGS();
     zval *filehandle = NULL;
 
     if (zend_parse_parameters(argc TSRMLS_CC, "r", &filehandle) == FAILURE) {
          return;
     }
 
     if (zend_list_delete(Z_RESVAL_P(filehandle)) == FAILURE) {
          RETURN_FALSE;
     }
 
     RETURN_TRUE;
}
参考:

[!--infotagslink--]

相关文章

  • PHP传值到不同页面的三种常见方式及php和html之间传值问题

    在项目开发中经常见到不同页面之间传值在web工作中,本篇文章给大家列出了三种常见的方式。接触PHP也有几个月了,本文总结一下这段日子中,在编程过程里常用的3种不同页面传值方法,希望可以给大家参考。有什么意见也希望大...2015-11-24
  • js修改input的type属性问题探讨

    js修改input的type属性有些限制。当input元素还未插入文档流之前,是可以修改它的值的,在ie和ff下都没问题。但如果input已经存在于页面,其type属性在ie下就成了只读属性了,不可以修改。...2013-10-19
  • Mysql常见问题集锦

    1,utf8_bin跟utf8_general_ci的区别 ci是 case insensitive, 即 "大小写不敏感", a 和 A 会在字符判断中会被当做一样的; bin 是二进制, a 和 A 会别区别对待. 例如你运行: SELECT * FROM table WHERE txt = 'a'...2013-10-04
  • Mysql大小写敏感的问题

    一、1 CREATE TABLE NAME(name VARCHAR(10)); 对这个表,缺省情况下,下面两个查询的结果是一样的:复制代码 代码如下: SELECT * FROM TABLE NAME WHERE name='clip'; SELECT * FROM TABLE NAME WH...2015-03-15
  • linux mint 下mysql中文支持问题

    一.mysql默认不支持中文,它的server和db默认是latin1编码.所以我们要将其改变为utf-8编码,因为utf-8包含了地球上大部分语言的二进制编码 1.关闭mysql服务 sudo /etc/init.d/mysql stop 2.修改mysql配置文件 mysql配...2015-10-21
  • PHP分布式框架如何使用Memcache同步SESSION教程

    本教程主要讲解PHP项目如何用实现memcache分布式,配置使用memcache存储session数据,以及memcache的SESSION数据如何同步。 至于Memcache的安装配置,我们就不讲了,以前...2016-11-25
  • PHP+memcache实现消息队列案例分享

    memche消息队列的原理就是在key上做文章,用以做一个连续的数字加上前缀记录序列化以后消息或者日志。然后通过定时程序将内容落地到文件或者数据库。php实现消息队列的用处比如在做发送邮件时发送大量邮件很费时间的问...2014-05-31
  • C#使用队列(Queue)解决简单的并发问题

    这篇文章主要介绍了使用队列(Queue)解决简单的并发问题,讲解的很细致,喜欢的朋友们可以了解一下...2020-06-25
  • windows 10 安装和使用中5个常见问题

    2015年7月29日0点起,Windows 10推送全面开启,Windows7、Windows8.1用户可以免费升级到Windows 10,用户也可以通过系统升级到Windows10,在这过程中,用户会遇到这样那样的问题,下面小编总结了windows 10 安装和使用中5个常见问题,需要的朋友可以参考下...2016-01-27
  • php中session常见问题分析

    PHP的session功能,一直为许多的初学者为难。就连有些老手,有时都被搞得莫名其妙。本文,将这些问题,做一个简单的汇总,以便大家查阅。 1. 错误提示 引用 代...2016-11-25
  • javascript学习指南之回调问题

    回调函数被认为是一种高级函数,一种被作为参数传递给另一个函数(在这称作"otherFunction")的高级函数,回调函数会在otherFunction内被调用(或执行)。回调函数的本质是一种模式(一种解决常见问题的模式),因此回调函数也被称为回调模式。...2016-04-25
  • json error: Use of overloaded operator [] is ambiguous错误的解决方法

    今天小编就为大家分享一篇关于json error: Use of overloaded operator [] is ambiguous错误的解决方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...2020-04-25
  • C++基于递归算法解决汉诺塔问题与树的遍历功能示例

    这篇文章主要介绍了C++基于递归算法解决汉诺塔问题与树的遍历功能,简单描述了递归算法的原理,并结合实例形式分析了基于递归算法解决汉诺塔问题与数的遍历相关操作技巧,需要的朋友可以参考下...2020-04-25
  • Windows下Memcache的安装方法

    很多phper不知道如何在Windows下搭建Memcache的开发调试环境,最近个人也在研究Memcache,记录下自己安装搭建的过程。 ...2016-01-27
  • PHP date函数显示1970-01-01问题详解

    我们使用date函数直接显示后面带有date("Y-m-d H:i:s",$t);发现显示的为1970-01-01了,这个问题对于新手来讲可能不好理解,但对于做过几年的高手来讲小菜了。 如date...2016-11-25
  • 在Mac OS的PHP环境下安装配置MemCache的全过程解析

    这篇文章主要介绍了在Mac OS的PHP环境下安装配置MemCache的全过程解析,MemCache是一套分布式的高速缓存系统,需要的朋友可以参考下...2016-02-18
  • C#约瑟夫问题解决方法

    这篇文章主要介绍了C#约瑟夫问题解决方法,较为详细的分析了约瑟夫问题及C#解决技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • 学习动态网页PHP技术常见问题汇总解答

    1:为什么我得不到变量 我在一网页向另一网页POST数据name,为什么输出$name时却得不到任何值? 在PHP4.2以后的版本中reGISter_global默认为off 若想取得从另一页...2016-11-25
  • IIS 配置问题 一些iis常见问题的解决方法

    前几天在IIS的配置上出了些问题,到网上查找了些资料,顺便整理放在这里,希望对大家有帮助 ...2016-01-27
  • php memcache和php memcached比较以及问题

    php memcache和php memcached是php的memcache分布式的高速缓存系统的两个客户端,php memcache是老客户端,php memcached是功能更加完善的新的代替php memcached的。...2016-11-25