PHP扩展开发-用魔术方法扩展session类

现在有一个简单的session类,来实现项目中session的统一管理.此session类可以设置session变量名前缀,使用魔术方法来注册和检查session变量,使用起来非常方便。代码如下:

<?php
/*
author:dengqiang
*/
class session {
	private $prefix;
	
	public function __construct($prefix) {
		@session_start ();
		$this->prefix = $prefix;
	}
	
	public function setPrefix() {
		return $this->prefix;
	}
	
	public function getPrefix() {
		return $this->prefix;
	}
	
	public function delete($name) {
		if (isset ( $_SESSION [$this->prefix . $name] )) {
			unset ( $_SESSION [$this->prefix . $name] );
		}
	}
	
	public function __set($name, $value) {
		$_SESSION [$this->prefix . $name] = $value;
	}
	
	public function __get($name) {
		if (isset ( $_SESSION [$this->prefix . $name] )) {
			return $_SESSION [$this->prefix . $name];
		} else {
			return null;
		}
	}
	
	public function isset($name){
		return isset($_SESSION [$this->prefix . $name]);
	}
	
	public function unset($name){
		unset($_SESSION [$this->prefix . $name]);
		return true;
	}	
}
?>
现在我们将此session类开发成php扩展类,类名为Mysession。使用到的相关ZEND宏和PHPAPI如下:
PS(session_status) //用于获取当前session状态
PS_ADD_VARL()//注册一个PS全局变量
PS_DEL_VARL()//删除PS全局变量
zend_delete_global_variable()//删除zend全局变量
php_set_session_var()//设置session变量
php_get_session_var


在php_mysession.h声明Mysession类和方法

PHP_METHOD(Mysession, __construct);	
PHP_METHOD(Mysession, setPrefix);	
PHP_METHOD(Mysession, getPrefix);	
PHP_METHOD(Mysession, delete);
PHP_METHOD(Mysession, isset);	
PHP_METHOD(Mysession, unset);	
PHP_METHOD(Mysession, __set);	
PHP_METHOD(Mysession, __get);
在mysession.c中实现Mysession类扩展
加载session头文件
#include "ext/session/php_session.h"

#define IF_SESSION_VARS() \
    if (PS(http_session_vars) && PS(http_session_vars)->type == IS_ARRAY)
声明方法中的参数



ZEND_BEGIN_ARG_INFO(arg_construct,1)
ZEND_ARG_INFO(0, prefix)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_setPrefix,1)
ZEND_ARG_INFO(0, prefix)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_set,2)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_get,1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_isset,1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arg_unset,1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

将Mysession类注册到zend内部

static zend_function_entry Mysession_class_functions[] = {
	PHP_ME(Mysession, __construct , arg_construct, ZEND_ACC_CTOR | ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, setPrefix , arg_setPrefix, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, getPrefix ,NULL, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, delete  ,NULL, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, isset  ,arg_isset, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, unset  ,arg_unset, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, __set  , arg_set, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	PHP_ME(Mysession, __get  ,arg_get, ZEND_ACC_PUBLIC)	/* For testing, remove later. */
	{NULL, NULL, NULL}
};


zend_class_entry *Mysession_ce;
PHP_MINIT_FUNCTION(mysession)
{
	/* If you have INI entries, uncomment these lines 
	REGISTER_INI_ENTRIES();
	*/
	zend_class_entry Mysession;
	INIT_CLASS_ENTRY(Mysession, "Mysession", Mysession_class_functions); 
	Mysession_ce = zend_register_internal_class_ex(&Mysession, NULL, NULL TSRMLS_CC); 
	zend_declare_property_null(Mysession_ce, ZEND_STRL("_prefix"), ZEND_ACC_PRIVATE TSRMLS_CC); //声明session前缀私有变量
	return SUCCESS;
}

添加开发者信息


PHP_MINFO_FUNCTION(mysession)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "mysession support", "enabled");
	php_info_print_table_row(2, "author", "Dengqiang");
	php_info_print_table_row(2, "version", "1.0");

	php_info_print_table_end();

	/* Remove comments if you have entries in php.ini
	DISPLAY_INI_ENTRIES();
	*/
}
实现Mysession类中方法
PHP_METHOD(Mysession, __construct)
{
	char *prefix="";
	int prefix_len=0;
	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &prefix, &prefix_len) == FAILURE){
		return;
	}

	if(ZEND_NUM_ARGS()>0){
		zend_update_property_string(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), prefix TSRMLS_CC); 
	}

	if (PS(session_status) != php_session_active && PS(session_status) != php_session_disabled) {
		php_session_start(TSRMLS_C);
	}

	RETURN_TRUE;
}

PHP_METHOD(Mysession, setPrefix)
{
	char *prefix;
	int prefix_len=0;
	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prefix, &prefix_len) == FAILURE){
		return;
	}

	if(prefix_len>0){
		zend_update_property_string(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), prefix TSRMLS_CC); 
		RETURN_TRUE;
	}
	RETURN_FALSE;
	
}

PHP_METHOD(Mysession, getPrefix)
{
	zval *zPrefix;
	char *prefix;
    zPrefix = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), 0 TSRMLS_CC); 
    prefix = Z_STRVAL_P(zPrefix);

	if(prefix != NULL){
		RETURN_STRINGL(prefix, strlen(prefix), 0);
	}
	
	RETURN_NULL();
	
}

PHP_METHOD(Mysession, delete)
{
	char *p_name;
	int p_name_len;
	char *session_name;
	int session_name_len;
	zval *zPrefix;
	char *prefix;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p_name, &p_name_len) == FAILURE) {
		return;
	}

	if (PS(session_status) == php_session_none) {
		RETURN_FALSE;
	}

	zPrefix = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), 0 TSRMLS_CC); 
    prefix = Z_STRVAL_P(zPrefix) == NULL ? "":Z_STRVAL_P(zPrefix);

	session_name_len = spprintf(&session_name, 0, "%s%s", prefix, p_name);

	IF_SESSION_VARS() {
		SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
		PS_DEL_VARL(session_name, session_name_len);

	}

	RETURN_TRUE;
}

PHP_METHOD(Mysession, isset)
{
	zval *p_var;
	char *p_name;
	int p_name_len;
	char *session_name;
	int session_name_len;
	zval *zPrefix;
	char *prefix;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p_name, &p_name_len) == FAILURE) {
		return;
	}

	if (PS(session_status) == php_session_none) {
		RETURN_FALSE;
	}

	zPrefix = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), 0 TSRMLS_CC); 
    prefix = Z_STRVAL_P(zPrefix);

	session_name_len = spprintf(&session_name, 0, "%s%s", prefix, p_name);

	IF_SESSION_VARS() {
		if (zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), session_name, session_name_len+1, (void **)&p_var) == SUCCESS) {
			RETURN_TRUE;
		}
	}
	RETURN_FALSE;
}

PHP_METHOD(Mysession, unset)
{
	if (PS(session_status) == php_session_none) {
		RETURN_FALSE;
	}

	IF_SESSION_VARS() {
		HashTable *ht_sess_var;

		SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
		ht_sess_var = Z_ARRVAL_P(PS(http_session_vars));

		if (PG(register_globals)) {
			uint str_len;
			char *str;
			ulong num_key;
			HashPosition pos;

			zend_hash_internal_pointer_reset_ex(ht_sess_var, &pos);

			while (zend_hash_get_current_key_ex(ht_sess_var, &str, &str_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING) {
				zend_delete_global_variable(str, str_len - 1 TSRMLS_CC);
				zend_hash_move_forward_ex(ht_sess_var, &pos);
			}
		}

		/* Clean $_SESSION. */
		zend_hash_clean(ht_sess_var);
	}
}

PHP_METHOD(Mysession, __set)
{
	zval *value = NULL;
	char *name;
	char *session_name;
	int name_len,session_name_len;
	zval *zPrefix;
	char *prefix;


	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &value) == FAILURE) {
		return;
	}

	if (PS(session_status) == php_session_none || PS(session_status) == php_session_disabled) {
		RETURN_FALSE;
	}


	zPrefix = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), 0 TSRMLS_CC); 
    prefix = Z_STRVAL_P(zPrefix) == NULL ? "":Z_STRVAL_P(zPrefix);


	session_name_len = spprintf(&session_name, 0, "%s%s", prefix, name);

	IF_SESSION_VARS() {
		SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
		PS_DEL_VARL(session_name, session_name_len);
	}


	php_set_session_var(session_name, session_name_len, value, NULL  TSRMLS_CC);

	PS_ADD_VARL(session_name, session_name_len);

}

PHP_METHOD(Mysession, __get)
{
	zval **p_var;
	char *name;
	char *session_name;
	int name_len,session_name_len;
	zval *zPrefix;
	char *prefix;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
		return;
	}

	if (PS(session_status) == php_session_none || PS(session_status) == php_session_disabled) {
		RETURN_FALSE;
	}


	zPrefix = zend_read_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("_prefix"), 0 TSRMLS_CC); 
     prefix = Z_STRVAL_P(zPrefix) == NULL ? "":Z_STRVAL_P(zPrefix);

	session_name_len = spprintf(&session_name, 0, "%s%s", prefix, name);

	IF_SESSION_VARS() {
		if (php_get_session_var(session_name, session_name_len, &p_var) == SUCCESS) {
			*return_value = **p_var;
		}
	}

	
}

编译安装后重启php-fpm测试

<?php


$Mysession = new Mysession('test');

$Mysession->var1 = "string";
var_dump($Mysession->isset('var1'));
echo"<br>";
var_dump($Mysession->var1);
echo"<br>";

$Mysession->var2 = array("a"=>'kingsoft', "b"=>"dengqiang");
var_dump($Mysession->isset('var2'));
echo"<br>";
var_dump($Mysession->var2);
echo"<br>";

$Mysession->delete('var1');
var_dump($Mysession->var1);
echo"<br>";

$Mysession->unset();
var_dump($Mysession->var2);


结果:

      整个Mysession类扩展已开发完毕,我们可以发现PHP扩展类和php程序自定义类是非常相似的。以魔术方法__set为例,在php程序中,它会将未定义的属性和值解析为第一个和第二个参数,在PHP扩展中__set方法同样是接收属性名称和属性值两个参数。还一点就是在扩展中构造方法开启一次session后在其他方法中无需再次开启,这与php程序中自定义Mysession类也是一致的。

      不管是php中自定义类还是PHP内核扩展类,他们的工作机制都是一样的,php自定义类可以理解为PHP内核扩展类再次封装了一层,PHP内核扩展的意义也是少做一次php代码的解析。

转载于:https://my.oschina.net/u/554660/blog/173428

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值