[svn:PHP-Sandwich] rev 1072 - PHP-Sandwich/trunk

[email protected] 7 Jun 2005 14:37:36 -0000
Newsgroups perl.php.sandwich.dev
Message-ID <[email protected]>
Author: gschlossnagle
Date: Tue Jun  7 07:37:35 2005
New Revision: 1072

Modified:
   PHP-Sandwich/trunk/PHP.xs
   PHP-Sandwich/trunk/phpfuncs.c
   PHP-Sandwich/trunk/phpfuncs.h
   PHP-Sandwich/trunk/phpinterp.c
   PHP-Sandwich/trunk/phpinterp.h
Log:
Flesh out support for passing perl classes into PHP, and have them 
actable on.  The get_class_name thing is a hack, but I think it
is the best solution.



Modified: PHP-Sandwich/trunk/PHP.xs
==============================================================================
--- PHP-Sandwich/trunk/PHP.xs	(original)
+++ PHP-Sandwich/trunk/PHP.xs	Tue Jun  7 07:37:35 2005
@@ -11,6 +11,7 @@
 #endif
 
 #include "phpinterp.h"
+#include "phpfuncs.h"
 
 #if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
 
@@ -54,7 +55,7 @@ static int zval_is_assoc(zval *zptr)
   return 0;
 }
 
-zval *SvZval(SV *sv)
+zval *SvZval(SV *sv TSRMLS_DC)
 {
   SV *orig_sv;
   zval *retval = NULL;
@@ -62,7 +63,6 @@ zval *SvZval(SV *sv)
   MAKE_STD_ZVAL(retval);
 
   /* derference sv as much as possible */
-  fprintf(stderr, "sv: %p\n", sv);
   orig_sv = sv;
   while(SvROK(sv) && !SvMAGICAL(sv)) {
     sv = SvRV(sv);
@@ -103,7 +103,7 @@ zval *SvZval(SV *sv)
         for(i = 0; i < cnt; i++) {
           element = av_fetch((AV *)sv, i, 0);
           if(element) {
-            add_index_zval(retval, i, SvZval(*element));
+            add_index_zval(retval, i, SvZval(*element TSRMLS_CC));
           }
         }
       }
@@ -129,7 +129,7 @@ zval *SvZval(SV *sv)
         array_init(retval);
         hv_iterinit((HV *)sv);
         while((element = hv_iternextsv((HV *)sv, &key, &key_len)) != NULL) {
-          add_assoc_zval_ex(retval, key, key_len + 1, SvZval(element));
+          add_assoc_zval_ex(retval, key, key_len + 1, SvZval(element TSRMLS_CC));
         }
       }
       break;
@@ -137,8 +137,8 @@ zval *SvZval(SV *sv)
       fprintf(stderr, "SVt_PVCV\n");
       break;
     case SVt_PVGV: /* glob */
-      fprintf(stderr, "SVt_PVGV\n");
-      sv_dump(sv);
+      /* use orig_sv here to avoid losing your bless */
+      plsv_wrap_sv(retval, orig_sv TSRMLS_CC);
       break;
     case SVt_PVMG: /* magic */
       if(sv_isobject(orig_sv)) {
@@ -147,8 +147,10 @@ zval *SvZval(SV *sv)
           retval = prsrc->val;
         } else {
           /* should wrap me in a zend object */
+          plsv_wrap_sv(retval, orig_sv TSRMLS_CC);
         }
       } else {
+        fprintf(stderr, "[%s:%d] can I be here?\n", __FILE__, __LINE__);
         // do something else
       }
       break;
@@ -156,7 +158,6 @@ zval *SvZval(SV *sv)
       fprintf(stderr, "SVt_PVLV\n");
       break;
     default:
-      fprintf(stderr, "SVt_??? default\n");
       ZVAL_NULL(retval);
       break;
   }
@@ -168,132 +169,143 @@ SV *newSVzval(zval *zptr, PHP_Interprete
   SV *retval;
   void *old_ctx;
   old_ctx = tsrm_set_interpreter_context(interp->ctx);
-  switch( zptr->type) {
-    case IS_NULL:
-      retval = &PL_sv_undef;
-      break;
-    case IS_LONG:
-      retval =  newSViv(Z_LVAL_P(zptr));
-      break;
-    case IS_DOUBLE:
-      retval =  newSVnv(Z_DVAL_P(zptr));
-      break;
-    case IS_BOOL:
-      retval = Z_BVAL_P(zptr) ? &PL_sv_yes : &PL_sv_no;
-      break;
-    case IS_ARRAY:
-      {
-        zval **entry;
-        HashPosition pos;
-        char *sk;
-        uint skl;
-        ulong nk;
-        int is_assoc = 0;
-        if(zval_is_assoc(zptr)) {
-          retval = (SV *) newHV();
-          is_assoc = 1;
-        } else {
-          retval = (SV *) newAV();
-          is_assoc = 0;
+  {
+    TSRMLS_FETCH();
+    switch( zptr->type) {
+      case IS_NULL:
+        retval = &PL_sv_undef;
+        break;
+      case IS_LONG:
+        retval =  newSViv(Z_LVAL_P(zptr));
+        break;
+      case IS_DOUBLE:
+        retval =  newSVnv(Z_DVAL_P(zptr));
+        break;
+      case IS_BOOL:
+        retval = Z_BVAL_P(zptr) ? &PL_sv_yes : &PL_sv_no;
+        break;
+      case IS_ARRAY:
+        {
+          zval **entry;
+          HashPosition pos;
+          char *sk;
+          uint skl;
+          ulong nk;
+          int is_assoc = 0;
+          if(zval_is_assoc(zptr)) {
+            retval = (SV *) newHV();
+            is_assoc = 1;
+          } else {
+            retval = (SV *) newAV();
+            is_assoc = 0;
+          }
+          zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zptr), &pos);
+          while(zend_hash_get_current_data_ex(Z_ARRVAL_P(zptr), (void **)&entry, &pos) == SUCCESS) {
+            switch(zend_hash_get_current_key_ex(Z_ARRVAL_P(zptr), &sk, &skl, &nk, 1, &pos)) {
+              case HASH_KEY_IS_STRING:
+                if(!is_assoc) { 
+                  /* something bad has happened here */ 
+                }
+                else {
+                  hv_store((HV *) retval, sk, skl - 1, newSVzval(*entry, interp), 0);
+                }
+                break;
+              case HASH_KEY_IS_LONG:
+                if(is_assoc) {
+                  char buf[32];
+                  snprintf(buf, sizeof(buf), "%d", nk);
+                  hv_store((HV *) retval, buf, strlen(buf), newSVzval(*entry, interp), 0);
+                } else {
+                  av_store((AV *) retval, nk, newSVzval(*entry, interp));
+                }
+                break;
+            }
+            zend_hash_move_forward_ex(Z_ARRVAL_P(zptr), &pos);
+          }
+          retval = newRV_noinc(retval);
         }
-        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zptr), &pos);
-        while(zend_hash_get_current_data_ex(Z_ARRVAL_P(zptr), (void **)&entry, &pos) == SUCCESS) {
-          switch(zend_hash_get_current_key_ex(Z_ARRVAL_P(zptr), &sk, &skl, &nk, 1, &pos)) {
-            case HASH_KEY_IS_STRING:
-              if(!is_assoc) { 
-                /* something bad has happened here */ 
-              }
-              else {
-                hv_store((HV *) retval, sk, skl - 1, newSVzval(*entry, interp), 0);
+        break;
+      case IS_OBJECT:
+          {
+            char *name;
+            zend_uint namelen;
+            char objectname[MAXPATHLEN];
+            HV *h1, *package;
+            SV * c1;
+            PHP_Class pclass;
+  
+            /* this is the special case that this is a perl object returning to us */
+            if(Z_OBJCE_P(zptr) == plsv_ce) {
+              struct plsv *pl;
+              pl = (struct plsv *) zend_object_store_get_object(zptr TSRMLS_CC);
+              SvREFCNT_inc(pl->sv);
+              retval = pl->sv;
+            } else {
+              c1 = newSV(0);
+              pclass = malloc(sizeof(*pclass));
+              /* FIXME: don't leak! */
+    
+              MAKE_STD_ZVAL(pclass->val);
+              ZVAL_ZVAL(pclass->val, zptr, 1, 0);
+              pclass->interp = interp;
+              sandwich_interp_inc_ref(interp);
+              if(get_class_name(zptr, &name, &namelen) < 0) {
+                name = "UNKNOWN";
               }
-              break;
-            case HASH_KEY_IS_LONG:
-              if(is_assoc) {
-                char buf[32];
-                snprintf(buf, sizeof(buf), "%d", nk);
-                hv_store((HV *) retval, buf, strlen(buf), newSVzval(*entry, interp), 0);
-              } else {
-                av_store((AV *) retval, nk, newSVzval(*entry, interp));
+              snprintf(objectname, MAXPATHLEN, "PHP::Class::%s", name);
+              sv_setref_pv(c1, "PHP::Class", (void *) pclass);
+              h1 = (HV *)sv_2mortal((SV *)newHV());
+              hv_magic(h1, (GV*)c1, PERL_MAGIC_tied);
+              sv_magic((SV *)h1, c1, PERL_MAGIC_ext, NULL, -1);
+              retval = newRV((SV *)h1);
+              package = gv_stashpv(objectname, TRUE);
+              {
+                char objectisa[MAXPATHLEN];
+                package = gv_stashpv(objectname, 1);
+                snprintf(objectisa, MAXPATHLEN, "PHP::Class::%s::ISA", name);
+                //if(get_av(objectisa, FALSE)) {
+                  av_push(get_av(objectisa, TRUE),
+                          newSVpv("PHP::Class", 0));
+                //}
               }
-              break;
+              retval = sv_bless(retval, package);
+            }
           }
-          zend_hash_move_forward_ex(Z_ARRVAL_P(zptr), &pos);
-        }
-        retval = newRV_noinc(retval);
-      }
-      break;
-    case IS_OBJECT:
-        {
-          char *name;
-          zend_uint namelen;
-          char objectname[MAXPATHLEN];
-          HV *h1, *package;
-          SV * c1;
-          PHP_Class pclass;
-
-          c1 = newSV(0);
-          pclass = malloc(sizeof(*pclass));
-          /* FIXME: don't leak! */
-
-          MAKE_STD_ZVAL(pclass->val);
-          ZVAL_ZVAL(pclass->val, zptr, 1, 0);
-          pclass->interp = interp;
-          sandwich_interp_inc_ref(interp);
-          if(get_class_name(zptr, &name, &namelen) < 0) {
-            name = "UNKNOWN";
-          }
-          snprintf(objectname, MAXPATHLEN, "PHP::Class::%s", name);
-          sv_setref_pv(c1, "PHP::Class", (void *) pclass);
-          h1 = (HV *)sv_2mortal((SV *)newHV());
-          hv_magic(h1, (GV*)c1, PERL_MAGIC_tied);
-          sv_magic((SV *)h1, c1, PERL_MAGIC_ext, NULL, -1);
-          retval = newRV((SV *)h1);
-          package = gv_stashpv(objectname, TRUE);
+        break;
+      case IS_STRING:
+        retval = newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
+        break;
+      case IS_RESOURCE:
           {
-            char objectisa[MAXPATHLEN];
-            package = gv_stashpv(objectname, 1);
-            snprintf(objectisa, MAXPATHLEN, "PHP::Class::%s::ISA", name);
-            //if(get_av(objectisa, FALSE)) {
-              av_push(get_av(objectisa, TRUE),
-                      newSVpv("PHP::Class", 0));
-            //}
+            SV * c1;
+            PHP_Resource prsrc;
+  
+            c1 = newSV(0);
+            prsrc = malloc(sizeof(*prsrc));
+            /* FIXME: don't leak! */
+            MAKE_STD_ZVAL(prsrc->val);
+            ZVAL_ZVAL(prsrc->val, zptr, 1, 0);
+            sandwich_interp_inc_ref(interp);
+            prsrc->interp = interp;
+            sv_setref_pv(c1, "PHP::Resource", (void *) prsrc);
+            retval = newSV(0);
+            sv_magic(retval, c1, PERL_MAGIC_tiedscalar, NULL, 0);
           }
-          retval = sv_bless(retval, package);
-        }
-      break;
-    case IS_STRING:
-      retval = newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
-      break;
-    case IS_RESOURCE:
-        {
-          SV * c1;
-          PHP_Resource prsrc;
-
-          c1 = newSV(0);
-          prsrc = malloc(sizeof(*prsrc));
-          /* FIXME: don't leak! */
-          MAKE_STD_ZVAL(prsrc->val);
-          ZVAL_ZVAL(prsrc->val, zptr, 1, 0);
-          sandwich_interp_inc_ref(interp);
-          prsrc->interp = interp;
-          sv_setref_pv(c1, "PHP::Resource", (void *) prsrc);
-          retval = newSV(0);
-          sv_magic(retval, c1, PERL_MAGIC_tiedscalar, NULL, 0);
-        }
-      break;
-    case IS_CONSTANT:
-      retval = newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
-      break;
-    case IS_CONSTANT_ARRAY:
-      fprintf(stderr, "Unimplemented type: IS_CONSTANT_ARRAY\n");
-      /* FIXME: return by copy, not by reference */
-      retval = &PL_sv_undef;
-      break;
-    default:
-      fprintf(stderr, "Unknown type %d in newSVzval()\n", zptr->type);
-      { char *ptr = NULL; *ptr = 1; }
-      retval = &PL_sv_undef;
-      break;
+        break;
+      case IS_CONSTANT:
+        retval = newSVpv(Z_STRVAL_P(zptr), Z_STRLEN_P(zptr));
+        break;
+      case IS_CONSTANT_ARRAY:
+        fprintf(stderr, "Unimplemented type: IS_CONSTANT_ARRAY\n");
+        /* FIXME: return by copy, not by reference */
+        retval = &PL_sv_undef;
+        break;
+      default:
+        fprintf(stderr, "Unknown type %d in newSVzval()\n", zptr->type);
+        { char *ptr = NULL; *ptr = 1; }
+        retval = &PL_sv_undef;
+        break;
+    }
   }
   tsrm_set_interpreter_context(old_ctx);
   return retval;
@@ -375,103 +387,98 @@ SV *SAND_call(method_name, interp, ...)
       char *croakstr = NULL;
 
       old_ctx = tsrm_set_interpreter_context(interp->ctx);
-      
-      INIT_ZVAL(method);
-      ZVAL_STRING(&method, method_name, 1);
-      if(items > 2) {
-        params = emalloc(sizeof(zval *) * (items - 2));
-        for(i = 2; i< items; i++) {
-          params[i - 2] = SvZval(ST(i));
-        }
-        param_count = items - 2;
-      }
-      retval = sandwich_call_function(interp, &method, params, param_count);
-      if(retval == NULL) {
-        croakstr = "A PHP error occured";
-        goto cleanup;
-      } else {
-        switch(retval->type) {
-          case IS_NULL:
-            RETVAL = &PL_sv_undef;
-            break;
-          case IS_LONG:
-          case IS_BOOL:
-          case IS_DOUBLE:
-          case IS_STRING:
-            RETVAL = newSVzval(retval, interp);
-            /*
-
-            SV * c1 = sv_newmortal();
-            RETVAL = newSV(0);
-            sv_setref_pv(c1, "PHP::Var::Scalar", (void *) retval);
-            sv_magic(RETVAL, c1, PERL_MAGIC_tiedscalar, NULL, 0);
-
-            */
-            break;
-          case IS_ARRAY:
-            RETVAL = newSVzval(retval, interp);
-            break;
-          case IS_OBJECT: 
-            {
-              char *name;
-              zend_uint namelen;
-              char objectname[MAXPATHLEN];
-              HV *h1, *package;
-              SV * c1;
-              PHP_Class pclass;
-
-              c1 = newSV(0);
-              pclass = malloc(sizeof(*pclass));
-              /* FIXME: don't leak! */
-              pclass->val = retval;
-              pclass->interp = interp;
-              sandwich_interp_inc_ref(interp);
-              if(get_class_name(retval, &name, &namelen) < 0) {
-                name = "UNKNOWN";
-              } 
-              snprintf(objectname, MAXPATHLEN, "PHP::Class::%s", name);
-              sv_setref_pv(c1, "PHP::Class", (void *) pclass);
-              h1 = (HV *)sv_2mortal((SV *)newHV());
-              hv_magic(h1, (GV*)c1, PERL_MAGIC_tied);
-              sv_magic((SV *)h1, c1, PERL_MAGIC_ext, NULL, -1);
-              RETVAL = newRV((SV *)h1);
-              package = gv_stashpv(objectname, TRUE);
-              {
-                char objectisa[MAXPATHLEN];
-                package = gv_stashpv(objectname, 1);
-                snprintf(objectisa, MAXPATHLEN, "PHP::Class::%s::ISA", name);
-                //if(get_av(objectisa, FALSE)) {
-                  av_push(get_av(objectisa, TRUE),
-                          newSVpv("PHP::Class", 0));
-                //}
-              }
-              RETVAL = sv_bless(RETVAL, package);
-            }
-            break;
-          case IS_RESOURCE:
+      {
+        TSRMLS_FETCH();
+        INIT_ZVAL(method);
+        ZVAL_STRING(&method, method_name, 1);
+        if(items > 2) {
+          params = emalloc(sizeof(zval *) * (items - 2));
+          for(i = 2; i< items; i++) {
+            params[i - 2] = SvZval(ST(i) TSRMLS_CC);
+          }
+          param_count = items - 2;
+        }
+        retval = sandwich_call_function(interp, &method, params, param_count);
+        if(retval == NULL) {
+          croakstr = "A PHP error occured";
+          goto cleanup;
+        } else {
+          RETVAL = newSVzval(retval, interp);
+          /*
+          switch(retval->type) {
+            case IS_NULL:
+              RETVAL = &PL_sv_undef;
+              break;
+            case IS_LONG:
+            case IS_BOOL:
+            case IS_DOUBLE:
+            case IS_STRING:
+              RETVAL = newSVzval(retval, interp);
+              break;
+            case IS_ARRAY:
+              RETVAL = newSVzval(retval, interp);
+              break;
+            case IS_OBJECT: 
               {
+                char *name;
+                zend_uint namelen;
+                char objectname[MAXPATHLEN];
+                HV *h1, *package;
                 SV * c1;
-                PHP_Resource prsrc;
-
+                PHP_Class pclass;
+  
                 c1 = newSV(0);
-                prsrc = malloc(sizeof(*prsrc));
-                /* FIXME: don't leak! */
-                prsrc->val = retval;
+                pclass = malloc(sizeof(*pclass));
+                pclass->val = retval;
+                pclass->interp = interp;
                 sandwich_interp_inc_ref(interp);
-                prsrc->interp = interp;
-                RETVAL = newSV(0);
-                sv_setref_pv(c1, "PHP::Resource", (void *) prsrc);
-                sv_magic(RETVAL, c1, PERL_MAGIC_tiedscalar, NULL, 0);
+                if(get_class_name(retval, &name, &namelen) < 0) {
+                  name = "UNKNOWN";
+                } 
+                snprintf(objectname, MAXPATHLEN, "PHP::Class::%s", name);
+                sv_setref_pv(c1, "PHP::Class", (void *) pclass);
+                h1 = (HV *)sv_2mortal((SV *)newHV());
+                hv_magic(h1, (GV*)c1, PERL_MAGIC_tied);
+                sv_magic((SV *)h1, c1, PERL_MAGIC_ext, NULL, -1);
+                RETVAL = newRV((SV *)h1);
+                package = gv_stashpv(objectname, TRUE);
+                {
+                  char objectisa[MAXPATHLEN];
+                  package = gv_stashpv(objectname, 1);
+                  snprintf(objectisa, MAXPATHLEN, "PHP::Class::%s::ISA", name);
+                  //if(get_av(objectisa, FALSE)) {
+                    av_push(get_av(objectisa, TRUE),
+                            newSVpv("PHP::Class", 0));
+                  //}
+                }
+                RETVAL = sv_bless(RETVAL, package);
               }
-            break;
-          default:
-            fprintf(stderr, "unsupported return type in PHP_Interpreter_call\n");
-            RETVAL = &PL_sv_undef;
-            break;
+              break;
+            case IS_RESOURCE:
+                {
+                  SV * c1;
+                  PHP_Resource prsrc;
+  
+                  c1 = newSV(0);
+                  prsrc = malloc(sizeof(*prsrc));
+                  prsrc->val = retval;
+                  sandwich_interp_inc_ref(interp);
+                  prsrc->interp = interp;
+                  RETVAL = newSV(0);
+                  sv_setref_pv(c1, "PHP::Resource", (void *) prsrc);
+                  sv_magic(RETVAL, c1, PERL_MAGIC_tiedscalar, NULL, 0);
+                }
+              break;
+            default:
+              fprintf(stderr, "unsupported return type in PHP_Interpreter_call\n");
+              RETVAL = &PL_sv_undef;
+              break;
+          }
+          */
         }
+  cleanup:
+        zval_dtor(&method);
       }
-cleanup:
-      zval_dtor(&method);
       tsrm_set_interpreter_context(old_ctx);
       if(croakstr) croak(croakstr);
     }
@@ -517,7 +524,7 @@ SV* SAND_instantiate(interp, class, ...)
         if(items > 2) {
           params = emalloc(sizeof(zval **) * (items - 2));
           for(i = 2; i< items; i++) {
-            zval *arg = SvZval(ST(i));
+            zval *arg = SvZval(ST(i) TSRMLS_CC);
             params[i - 2] = &arg;
           }
           param_count = items - 2;
@@ -593,7 +600,7 @@ SV* PHP_V_C_STORE(pclass, key, value)
         TSRMLS_FETCH();
 
         ce = zend_get_class_entry(pclass->val TSRMLS_CC);
-        tostore =  SvZval(value);
+        tostore =  SvZval(value TSRMLS_CC);
         if(tostore) zend_update_property(ce, pclass->val, key, strlen(key), tostore TSRMLS_CC);
         else croak("problem converting perl type to SV");
         RETVAL = newSVsv(value);
@@ -777,7 +784,7 @@ SV *PHP_V_C__AUTOLOAD(self, method_name,
         if(items > 2) {
           params = emalloc(sizeof(zval **) * (items - 2));
           for(i = 2; i< items; i++) {
-            zval *arg = SvZval(ST(i));
+            zval *arg = SvZval(ST(i) TSRMLS_CC);
             params[i - 2] = &arg;
           }
           param_count = items - 2;

Modified: PHP-Sandwich/trunk/phpfuncs.c
==============================================================================
--- PHP-Sandwich/trunk/phpfuncs.c	(original)
+++ PHP-Sandwich/trunk/phpfuncs.c	Tue Jun  7 07:37:35 2005
@@ -8,10 +8,13 @@
 ZEND_DECLARE_MODULE_GLOBALS(sandwich);
 zend_class_entry *pl_ce;
 zend_class_entry *plobj_ce;
+zend_class_entry *plsv_ce;
 
 static zend_object_handlers plobj_handlers;
+static zend_object_handlers plsv_handlers;
 
 static zend_object_value plobj_create_object(zend_class_entry *ce TSRMLS_DC);
+static zend_object_value plsv_create_object(zend_class_entry *ce TSRMLS_DC);
 
 
 PHP_MINFO_FUNCTION(sandwich)
@@ -67,7 +70,7 @@ sandwich_dim_read(zval *obj, zval *offse
     goto err_out;
   }
 
-  return_value = SvZval(value);
+  return_value = SvZval(value TSRMLS_CC);
   return return_value;
   
 err_out:
@@ -120,7 +123,7 @@ PHP_METHOD(perl, getvariable)
   }
       
   if (var != NULL) {
-    retval = SvZval(var);
+    retval = SvZval(var TSRMLS_CC);
     RETURN_ZVAL(retval, 1, 0);
   } else {
     RETURN_NULL();
@@ -225,7 +228,7 @@ static int _sandwich_call_method(char *m
     */
     SvREFCNT_inc(prv);
     PUTBACK;
-    retval = SvZval(prv);
+    retval = SvZval(prv TSRMLS_CC);
     RETURN_ZVAL(retval, 1, 0);
     SvREFCNT_dec(prv);
     FREETMPS;
@@ -351,12 +354,134 @@ PHP_METHOD(perl, eval)
   if((rv = sandwich_perl_eval(aTHX_ func)) == NULL)  { 
     fprintf(stderr, "eval returned null\n"); 
   } else {
-    zval *retval = SvZval(rv);
+    zval *retval = SvZval(rv TSRMLS_CC);
     RETURN_ZVAL(retval, 1, 0);
     SvREFCNT_dec(rv);
   }
 }
 
+static int _sv_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS, int offset)
+{
+  struct plsv *pl;
+  SV           *var;
+  zval         *retval;
+  char         *name;
+  int           namelen;
+  zval         *param;
+  zval         ***args;
+  SV           *sparam;
+  int          argc, i;
+  SV           *prv;
+  pTHX;
+
+  pl = zend_object_store_get_object(getThis() TSRMLS_CC);
+#ifdef USE_ITHREADS
+  aTHX = pl->perl;
+#endif
+  {
+    dSP;
+  
+    argc = ZEND_NUM_ARGS();
+    args = (zval ***) safe_emalloc(sizeof(zval **), argc, 0);
+    if(zend_get_parameters_array_ex(argc, args) == FAILURE) {
+      efree(args);
+      WRONG_PARAM_COUNT;
+    }
+    
+    pl = zend_object_store_get_object(getThis() TSRMLS_CC);
+#ifdef USE_ITHREADS
+    aTHX = pl->perl;
+#endif  
+    ENTER;
+    SAVETMPS;
+    PUSHMARK(SP);
+    SvREFCNT_inc(pl->sv);
+    XPUSHs(pl->sv);
+    for(i = offset; i < argc; i++) {
+      var = newSVzval(*args[i], SandwichG(php));
+      var = sv_2mortal(var);
+      XPUSHs(var);
+    }
+    PUTBACK;
+    call_method(method, G_SCALAR);
+    SvREFCNT_dec(pl->sv);
+    SPAGAIN;
+    prv = POPs;
+    /*
+    if(coe && SvTRUE(ERRSV)) {
+      croak(SvPVx(ERRSV, n_a));
+    }
+    */
+    SvREFCNT_inc(prv);
+    PUTBACK;
+    retval = SvZval(prv TSRMLS_CC);
+    RETURN_ZVAL(retval, 1, 0);
+    SvREFCNT_dec(prv);
+    FREETMPS;
+    LEAVE;
+    efree(args);
+  }
+}
+
+static PHP_FUNCTION(sv_method_handler)
+{
+  _sv_call_method(
+    ((zend_internal_function*)EG(function_state_ptr)->function)->function_name,
+    INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+
+static int sv_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
+{
+  return _sv_call_method(method, INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+
+static union _zend_function *sv_get_method(zval **object_ptr, char *name, int len TSRMLS_DC)
+{
+  zval *object = *object_ptr;
+  zend_internal_function f, *fptr = NULL;
+  union _zend_function *func;
+  struct plobj *pl;
+  char *lc_method_name;
+
+  lc_method_name = emalloc(len + 1);
+  zend_str_tolower_copy(lc_method_name, name, len);
+  if (zend_hash_find(&plobj_ce->function_table, lc_method_name, len+1, (void**)&func) == SUCCESS) {
+    efree(lc_method_name);
+    return func;
+  }
+  efree(lc_method_name);
+  
+  f.type = ZEND_OVERLOADED_FUNCTION;
+  f.num_args = 0;
+  f.arg_info = NULL;
+  f.scope = plobj_ce;
+  f.fn_flags=0;
+  f.function_name= estrndup(name, len);
+  f.handler= PHP_FN(sv_method_handler);
+
+  func = emalloc(sizeof(*func));
+  memcpy(func, &f,sizeof(f));
+  return func;
+}
+
+int sv_get_class_name(zval *obj, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) {
+  if(parent) {
+    *class_name_len = strlen("PerlSV") + 1;
+    *class_name = estrndup("PerlSV", *class_name_len);
+  } else {
+    struct plsv *pl;
+    char *tmp;
+    pl = (struct plsv *) zend_object_store_get_object(obj TSRMLS_CC);
+    tmp = HvNAME((SvSTASH(SvRV(pl->sv))));
+    if(!tmp) return FAILURE;
+    *class_name_len = strlen(tmp) + sizeof("PerlSV::");
+    *class_name = emalloc(*class_name_len);
+    strncpy(*class_name, "PerlSV::", sizeof("PerlSV::"));
+    strcat(*class_name, tmp);
+    return SUCCESS;
+  }
+}
+
 static function_entry pl_functions[] = {
   PHP_ME(perl, getinstance, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   {NULL, NULL, NULL}
@@ -370,6 +495,10 @@ static function_entry plobj_functions[] 
   {NULL, NULL, NULL}
 };
 
+static function_entry plsv_functions[] = {
+  {NULL, NULL, NULL}
+};
+
 static void 
 plobj_free(void *obj TSRMLS_DC)
 {
@@ -438,12 +567,101 @@ plobj_create_object(zend_class_entry *ce
 
   return obj;
 }
+
+
+static void 
+plsv_free(void *obj TSRMLS_DC)
+{
+  struct plsv *pl;
+
+  pl = (struct plsv *) obj;
+  zend_hash_destroy(pl->zo.properties);
+  FREE_HASHTABLE(pl->zo.properties);
+
+  efree(obj);
+}
+
+static void
+plsv_dtor(void *obj, zend_object_handle handle TSRMLS_DC)
+{
+  struct plsv *pl;
+  dTHX;
+
+  pl = (struct plsv *) obj;
+  SvREFCNT_dec(pl->sv);
+}
+
+static struct plsv *
+plsv_new(zend_class_entry *ce TSRMLS_DC)
+{
+  struct plsv      *pl;
+  zend_object_value  obj;
+  dTHX;
+  
+  pl = ecalloc(1, sizeof(*pl));
+  pl->zo.ce = ce;
+  
+  ALLOC_HASHTABLE(pl->zo.properties);
+  zend_hash_init(pl->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+#ifdef USE_ITHREADS
+  pl->perl = aTHX;
+#endif
+
+  return pl;
+}
+
+static void
+plsv_clone(void *obj, void **cp TSRMLS_DC)
+{
+  struct plsv *pl;
+  struct plsv *clone;
+
+  pl = (struct plsv *) obj;
+  
+  clone = plsv_new(pl->zo.ce TSRMLS_CC);
+  if (!clone) {
+    *cp = NULL;
+    return;
+  }
+
+  *cp = (void *) clone;
+}
+
+static zend_object_value 
+plsv_create_object(zend_class_entry *ce TSRMLS_DC)
+{
+  struct plsv      *pl;
+  zend_object_value  obj;
+  
+  pl = plsv_new(ce TSRMLS_CC);
+  
+  obj.handle = zend_objects_store_put(pl, plsv_dtor,
+      (zend_objects_free_object_storage_t) plsv_free, plsv_clone TSRMLS_CC);
+  obj.handlers = (zend_object_handlers *) &plsv_handlers;
+
+  return obj;
+}
+
+void plsv_wrap_sv(zval *retval, SV *sv TSRMLS_DC)
+{
+  struct plsv *pl;
+
+  object_init_ex(retval, plsv_ce);
+  retval->refcount = 1;
+  retval->is_ref = 1;
+
+  pl = (struct plsv *) zend_object_store_get_object(retval TSRMLS_CC);
+  SvREFCNT_inc(sv);
+  pl->sv = sv;
+}
  
 
 PHP_MINIT_FUNCTION(sandwich)
 {
   zend_class_entry pl;
   zend_class_entry plobj;
+  zend_class_entry plsv;
   
   ZEND_INIT_MODULE_GLOBALS(sandwich, sw_initglobals, NULL);
 
@@ -468,7 +686,23 @@ PHP_MINIT_FUNCTION(sandwich)
   plobj_handlers.write_dimension = sandwich_dim_write;
   plobj_handlers.get_method = sandwich_get_method;
   plobj_handlers.call_method = sandwich_call_method;
+
+  INIT_CLASS_ENTRY(plsv, "PerlSV", plsv_functions);
   
+  plsv.create_object = plsv_create_object;
+  plsv_ce = zend_register_internal_class(&plsv TSRMLS_CC);
+  if (!plsv_ce) {
+    return FAILURE;
+  }
+
+  memcpy(&plsv_handlers, zend_get_std_object_handlers(), 
+      sizeof(plsv_handlers));
+
+  plsv_handlers.read_dimension = sandwich_dim_read;
+  plsv_handlers.write_dimension = sandwich_dim_write;
+  plsv_handlers.get_method = sv_get_method;
+  plsv_handlers.call_method = sv_call_method;
+  plsv_handlers.get_class_name = sv_get_class_name;
   return SUCCESS;
 }
 

Modified: PHP-Sandwich/trunk/phpfuncs.h
==============================================================================
--- PHP-Sandwich/trunk/phpfuncs.h	(original)
+++ PHP-Sandwich/trunk/phpfuncs.h	Tue Jun  7 07:37:35 2005
@@ -21,11 +21,24 @@ struct plobj {
     PerlInterpreter *perl;
 };
 
+struct plsv {
+    zend_object zo;
+    SV *sv;
+    PerlInterpreter *perl;
+};
+
 struct perlistats {
   uint16_t ps_callcnt;
   uint16_t ps_varcnt;
 };
 
+extern ZEND_API zend_class_entry *pl_ce;
+extern ZEND_API zend_class_entry *plobj_ce;
+extern ZEND_API zend_class_entry *plsv_ce;
+
+void plsv_wrap_sv(zval *retval, SV *sv TSRMLS_DC);
+
+
 ZEND_BEGIN_MODULE_GLOBALS(sandwich)
     struct perlistats ps_stats;
     sandwich_per_interp *php;

Modified: PHP-Sandwich/trunk/phpinterp.c
==============================================================================
--- PHP-Sandwich/trunk/phpinterp.c	(original)
+++ PHP-Sandwich/trunk/phpinterp.c	Tue Jun  7 07:37:35 2005
@@ -237,7 +237,7 @@ SV *sandwich_eval(sandwich_per_interp *i
 cleanup:
   tsrm_set_interpreter_context(old_ctx);
   if(rv == -1) {
-    croak("error in eval");
+    croak("PHP Error in eval");
   } else {
     /* FIXME, do i need to copy retval? */
     return newSVzval(&retval, interp);

Modified: PHP-Sandwich/trunk/phpinterp.h
==============================================================================
--- PHP-Sandwich/trunk/phpinterp.h	(original)
+++ PHP-Sandwich/trunk/phpinterp.h	Tue Jun  7 07:37:35 2005
@@ -38,7 +38,7 @@ zval *sandwich_call_function(sandwich_pe
 #define sandwich_interp_inc_ref(interp)  interp->ref++
 #define sandwich_interp_dec_ref(interp)  if(--interp->ref == 0) sandwich_per_interp_shutdown(interp)
 
-zval *SvZval(SV *sv);
+zval *SvZval(SV *sv TSRMLS_DC);
 SV *newSVzval(zval *param, sandwich_per_interp *interp);
 
 #endif