Skip to content

Instantly share code, notes, and snippets.

@rsky
Created February 11, 2011 04:47
Show Gist options
  • Save rsky/821936 to your computer and use it in GitHub Desktop.
Save rsky/821936 to your computer and use it in GitHub Desktop.
PHP 5.3で演算子オーバーロード
--- php-5.3.5/Zend/zend_operators.c.orig 2010-06-27 02:14:33.000000000 +0900
+++ php-5.3.5/Zend/zend_operators.c 2011-02-11 13:45:33.000000000 +0900
@@ -45,6 +45,77 @@
#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
+static int operator_overload(zval *op1, zval *op2, const char *function_name, zval **retval_ptr_ptr TSRMLS_DC) /* {{{ */
+{
+ zval callable;
+ zval *retval, *op2_copy;
+ zval **params[1];
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ int result;
+
+ *retval_ptr_ptr = NULL;
+
+ ZVAL_STRING(&callable, function_name, 0);
+ INIT_PZVAL(&callable);
+
+ if (!zend_is_callable_ex(&callable, op1, IS_CALLABLE_CHECK_SILENT, NULL, NULL, &fcc, NULL TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ if (op2) {
+ ALLOC_ZVAL(op2_copy);
+ *op2_copy = *op2;
+ zval_copy_ctor(op2_copy);
+ INIT_PZVAL(op2_copy);
+ params[0] = &op2_copy;
+ } else {
+ op2_copy = NULL;
+ }
+ retval = NULL;
+
+ fci.size = sizeof(fci);
+ fci.function_table = &fcc.calling_scope->function_table;
+ fci.object_ptr = fcc.object_ptr;
+ fci.function_name = &callable;
+ fci.retval_ptr_ptr = &retval;
+ fci.param_count = op2 ? 1 : 0;
+ fci.params = op2 ? params : NULL;
+ fci.no_separation = 1;
+ fci.symbol_table = NULL;
+
+ result = zend_call_function(&fci, &fcc TSRMLS_CC);
+
+ if (EG(exception)) {
+ zend_error(E_ERROR, "Method %s::%s() must not throw an exception", Z_OBJCE_P(op1)->name, function_name);
+ result = FAILURE;
+ }
+
+ if (result == SUCCESS) {
+ *retval_ptr_ptr = retval;
+ } else if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+
+ if (op2_copy) {
+ zval_ptr_dtor(&op2_copy);
+ }
+
+ return result;
+}
+/* }}} */
+
+#define OPERATOR_OVERLOAD(result, function_name, op1, op2) \
+ if (Z_TYPE_P(op1) == IS_OBJECT) { \
+ zval *retval = NULL; \
+ if (operator_overload(op1, op2, "__" #function_name, &retval TSRMLS_CC) == SUCCESS) { \
+ *result = *retval; \
+ zval_copy_ctor(result); \
+ zval_ptr_dtor(&retval); \
+ return SUCCESS; \
+ } \
+ }
+
ZEND_API int zend_atoi(const char *str, int str_len) /* {{{ */
{
int retval;
@@ -760,6 +831,8 @@
zval op1_copy, op2_copy;
int converted = 0;
+ OPERATOR_OVERLOAD(result, add, op1, op2);
+
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
@@ -822,6 +895,8 @@
zval op1_copy, op2_copy;
int converted = 0;
+ OPERATOR_OVERLOAD(result, sub, op1, op2);
+
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
@@ -869,6 +944,8 @@
zval op1_copy, op2_copy;
int converted = 0;
+ OPERATOR_OVERLOAD(result, mul, op1, op2);
+
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
@@ -910,6 +987,8 @@
zval op1_copy, op2_copy;
int converted = 0;
+ OPERATOR_OVERLOAD(result, div, op1, op2);
+
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG):
@@ -975,6 +1054,8 @@
zval op1_copy, op2_copy;
long op1_lval;
+ OPERATOR_OVERLOAD(result, mod, op1, op2);
+
zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment