読者です 読者をやめる 読者になる 読者になる

DELAEMON BLOG

Live as if you were to die tomorrow. Learn as if you were to live forever.

PHP 拡張 演算子オーバーロード

$ git diff
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index cf3a908..27c27a2 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -30,6 +30,7 @@
 #include "zend_strtod.h"
 #include "zend_exceptions.h"
 #include "zend_closures.h"
+#include "zend_interfaces.h"
 
 #if ZEND_USE_TOLOWER_L
 #include <locale.h>
@@ -794,6 +795,13 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *
        zval op1_copy, op2_copy;
        int converted = 0;
 
+  if (Z_TYPE_P(op1) == IS_OBJECT && zend_hash_exists(&Z_OBJCE_P(op1)->function_table, "__add", strlen("__add") + 1)) {
+      zval* tmp;
+      zend_call_method_with_1_params(&op1, NULL, NULL, "__add", &tmp, op2);
+      ZVAL_ZVAL(result, tmp, 0, 1);
+      return SUCCESS;
+  }
+
        while (1) {
                switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
                        case TYPE_PAIR(IS_LONG, IS_LONG): {
@@ -856,6 +864,13 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *
        zval op1_copy, op2_copy;
        int converted = 0;
 
+  if (Z_TYPE_P(op1) == IS_OBJECT && zend_hash_exists(&Z_OBJCE_P(op1)->function_table, "__sub", strlen("__sub") + 1)) {
+      zval* tmp;
+      zend_call_method_with_1_params(&op1, NULL, NULL, "__sub", &tmp, op2);
+      ZVAL_ZVAL(result, tmp, 0, 1);
+      return SUCCESS;
+  }
+

makeしておく

hoge.php

<?php
class Hoge
{
    function __construct($value)
    {
        $this->value = $value;
    }

    function __add(Hoge $right)
    {
        return new Hoge($this->value + $right->value);
    }

    function __sub(Hoge $right)
    {
        return new Hoge($this->value - $right->value);
    }
}

$hoge = new Hoge(10) + new Hoge(2) - new Hoge(5);

var_dump($hoge);

実行するとこんな感じ

sapi/cli/php hoge.php
object(Hoge)#1 (1) {
  ["value"]=>
  int(7)
}