develooper Front page | perl.php.sandwich.dev | Postings from August 2005

[svn:PHP-Sandwich] r1446 - in PHP-Sandwich/trunk: . lib/PHP t

From:
gschlossnagle
Date:
August 1, 2005 16:00
Subject:
[svn:PHP-Sandwich] r1446 - in PHP-Sandwich/trunk: . lib/PHP t
Message ID:
20050801230035.22900.qmail@x1.develooper.com
Author: gschlossnagle
Date: Mon Aug  1 16:00:34 2005
New Revision: 1446

Modified:
   PHP-Sandwich/trunk/PHP.xs
   PHP-Sandwich/trunk/lib/PHP/Interpreter.pm
   PHP-Sandwich/trunk/phpinterp.c
   PHP-Sandwich/trunk/phpinterp.h
   PHP-Sandwich/trunk/t/7.t
Log:
make this stuff work with php-5.0

Modified: PHP-Sandwich/trunk/PHP.xs
==============================================================================
--- PHP-Sandwich/trunk/PHP.xs	(original)
+++ PHP-Sandwich/trunk/PHP.xs	Mon Aug  1 16:00:34 2005
@@ -200,7 +200,7 @@ SV *newSVzval(zval *zptr, PHP_Interprete
 {
   SV *retval;
   void *old_ctx;
-  old_ctx = tsrm_set_interpreter_context(interp->ctx);
+  INTERP_CTX_ENTER(interp->ctx);
   {
     TSRMLS_FETCH();
     switch( zptr->type) {
@@ -337,7 +337,7 @@ SV *newSVzval(zval *zptr, PHP_Interprete
         break;
     }
   }
-  tsrm_set_interpreter_context(old_ctx);
+  INTERP_CTX_LEAVE();
   return retval;
 }
 
@@ -455,7 +455,7 @@ SV* SAND_new(classname, ...)
         SV *trackvars;
         char *trackvars_key;
         I32 trackvars_keylen;
-        void *old_ctx = tsrm_set_interpreter_context(interp->ctx);
+        INTERP_CTX_ENTER(interp->ctx);
         TSRMLS_FETCH();
         hv_iterinit(args);
         while((trackvars = hv_iternextsv(args, &trackvars_key, &trackvars_keylen)) != NULL) {
@@ -518,7 +518,7 @@ SV* SAND_new(classname, ...)
           }
         }
         my_auto_globals_create_request(NULL TSRMLS_CC);
-        tsrm_set_interpreter_context(old_ctx);
+        INTERP_CTX_LEAVE();
       }
       RETVAL = newSV(0);
       sv_setref_pv(RETVAL, classname, (void *)interp);
@@ -542,7 +542,23 @@ SV *SAND_include(interp, file)
   char *file;
   CODE:
     {
-      if(sandwich_include(interp, file) == 0) {
+      if(sandwich_include(interp, file, 0) == 0) {
+        RETVAL = newSVsv(ST(0));
+      }
+      else {
+        croak("Error including %s\n", file);
+        RETVAL = &PL_sv_no;
+      }
+    }
+  OUTPUT:
+    RETVAL
+
+SV *SAND_include_once(interp, file)
+  PHP_Interpreter interp;
+  char *file;
+  CODE:
+    {
+      if(sandwich_include(interp, file, 1) == 0) {
         RETVAL = newSVsv(ST(0));
       }
       else {
@@ -563,9 +579,8 @@ SV *SAND_call(interp, method_name, ...)
       int i;
       int param_count = 0;
       zval *retval;
-      void *old_ctx;
       char *croakstr = NULL;
-      old_ctx = tsrm_set_interpreter_context(interp->ctx);
+      INTERP_CTX_ENTER(interp->ctx);
       {
         TSRMLS_FETCH();
         INIT_ZVAL(method);
@@ -580,18 +595,31 @@ SV *SAND_call(interp, method_name, ...)
         retval = sandwich_call_function(interp, &method, params, param_count);
         zval_dtor(&method);
         if(retval == NULL) {
-          tsrm_set_interpreter_context(old_ctx);
+          INTERP_CTX_LEAVE();
           croakstr = "A PHP error occured\n";
         } else {
           RETVAL = newSVzval(retval, interp);
         }
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
       if(croakstr) croak(croakstr);
     }
   OUTPUT:
     RETVAL
 
+SV *SAND_is_multithreaded(interp)
+  PHP_Interpreter interp;
+  CODE:
+    {
+#ifdef ZTS
+      RETVAL = &PL_sv_yes;
+#else 
+      RETVAL = &PL_sv_no;
+#endif
+    }
+  OUTPUT:
+    RETVAL
+
 SV *SAND_set_output_handler(interp, sv)
   PHP_Interpreter interp;
   SV *sv;
@@ -643,11 +671,9 @@ SV* SAND_instantiate(interp, class, ...)
   char *class;
   CODE:
     {
-      void *old_ctx;
       char *croakstr = NULL;
       zval *obj = NULL;
-      
-      old_ctx = tsrm_set_interpreter_context(interp->ctx);
+      INTERP_CTX_ENTER(interp->ctx);
       {
         zend_fcall_info fci;
         zval method;
@@ -697,7 +723,7 @@ SV* SAND_instantiate(interp, class, ...)
         }
       }
       if(obj) RETVAL = newSVzval(obj, interp);
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
       if(croakstr) croak(croakstr);
     }
   OUTPUT:
@@ -715,9 +741,7 @@ SV* PHP_V_C_FETCH(pclass, key)
     {
       zend_class_entry *ce;
       zval *retval;
-      void *old_ctx;
-
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
 
@@ -725,7 +749,7 @@ SV* PHP_V_C_FETCH(pclass, key)
         retval = zend_read_property(ce, pclass->val, key, strlen(key), 0 TSRMLS_CC);
         RETVAL = newSVzval(retval, pclass->interp);
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -738,9 +762,8 @@ SV* PHP_V_C_STORE(pclass, key, value)
     {
       zend_class_entry *ce;
       zval *retval;
-      void *old_ctx;
 
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         zval *tostore;
         TSRMLS_FETCH();
@@ -751,7 +774,7 @@ SV* PHP_V_C_STORE(pclass, key, value)
         else croak("problem converting perl type to SV");
         RETVAL = newSVsv(value);
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -764,9 +787,8 @@ SV* PHP_V_C_FIRSTKEY(pclass)
       ulong index;
       char buf[32];
       HashTable *properties;
-      void *old_ctx;
 
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
         properties = Z_OBJPROP_P(pclass->val);
@@ -785,7 +807,7 @@ SV* PHP_V_C_FIRSTKEY(pclass)
             break;
         }
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -801,7 +823,7 @@ SV* PHP_V_C_NEXTKEY(pclass, lastkey)
       HashTable *properties;
       void *old_ctx;
 
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
         properties = Z_OBJPROP_P(pclass->val);
@@ -820,7 +842,7 @@ SV* PHP_V_C_NEXTKEY(pclass, lastkey)
             break;
         }
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -835,7 +857,7 @@ SV* PHP_V_C_EXISTS(pclass, skey)
       HashTable *properties;
       void *old_ctx;
 
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
         properties = Z_OBJPROP_P(pclass->val);
@@ -846,7 +868,7 @@ SV* PHP_V_C_EXISTS(pclass, skey)
           RETVAL = &PL_sv_no;
         }
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -862,7 +884,7 @@ SV *PHP_V_C_DELETE(pclass, skey)
       zval zkey;
       void *old_ctx;
 
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
         properties = Z_OBJPROP_P(pclass->val);
@@ -880,7 +902,7 @@ SV *PHP_V_C_DELETE(pclass, skey)
         RETVAL = &PL_sv_yes;
         zval_dtor(&zkey);
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -891,7 +913,6 @@ SV *PHP_V_C__AUTOLOAD(self, method_name,
   CODE:
     {
       PHP_Interpreter_Class pclass;
-      void *old_ctx;
       MAGIC *mg;
       zval method;
       zval ***params = NULL;
@@ -907,7 +928,7 @@ SV *PHP_V_C__AUTOLOAD(self, method_name,
 
       interp = pclass->interp;
 
-      old_ctx = tsrm_set_interpreter_context(interp->ctx);
+      INTERP_CTX_ENTER(interp->ctx);
       {
         zend_fcall_info fci;
         TSRMLS_FETCH();
@@ -1043,7 +1064,7 @@ SV *PHP_V_C__AUTOLOAD(self, method_name,
           efree(fci.params);
         }
         zval_dtor(&method);
-        tsrm_set_interpreter_context(old_ctx);
+        INTERP_CTX_LEAVE();
       }
       if(croakstr) croak(croakstr);
     }
@@ -1062,12 +1083,12 @@ void PHP_V_C_DESTROY(in)
       if(!mg || !mg->mg_obj || !SvROK(mg->mg_obj) || !SvIOK(SvRV(mg->mg_obj))) return;
       pclass = (PHP_Interpreter_Class) SvIV(SvRV(mg->mg_obj));
       if(!pclass) return;
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         TSRMLS_FETCH();
         zval_ptr_dtor(&pclass->val);
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
       /* potentially shutdown ZE */
       sandwich_interp_dec_ref(pclass->interp);
       free(pclass);
@@ -1088,7 +1109,7 @@ SV* PHP_V_C_create(in, class, ...)
       if(!mg) return;
       pclass = (PHP_Interpreter_Class) SvIV(SvRV(mg->mg_obj));
       if(!pclass) return;
-      old_ctx = tsrm_set_interpreter_context(pclass->interp->ctx);
+      INTERP_CTX_ENTER(pclass->interp->ctx);
       {
         zend_fcall_info fci;
         zval method;
@@ -1116,7 +1137,7 @@ SV* PHP_V_C_create(in, class, ...)
           RETVAL = newSVzval(obj, pclass->interp);
         }
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
       if(croakstr) croak(croakstr);
     }
   OUTPUT:
@@ -1132,13 +1153,13 @@ PHP_Interpreter_Resource PHP_V_R_FETCH(z
   PHP_Interpreter_Resource rv;
   CODE:
     {
-      void *old_ctx = tsrm_set_interpreter_context(zptr->interp->ctx);
+      INTERP_CTX_ENTER(zptr->interp->ctx);
       RETVAL = malloc(sizeof(*RETVAL));
       MAKE_STD_ZVAL(RETVAL->val);
       ZVAL_ZVAL(RETVAL->val, zptr->val, 1, 0);
       RETVAL->interp = zptr->interp;
       sandwich_interp_inc_ref(zptr->interp);
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
     }
   OUTPUT:
     RETVAL
@@ -1155,12 +1176,12 @@ void PHP_V_R_DESTROY(prsrc)
   CODE:
     {
       if(!prsrc || !prsrc->interp) return;
-      void *old_ctx = tsrm_set_interpreter_context(prsrc->interp->ctx);
+      INTERP_CTX_ENTER(prsrc->interp->ctx);
       {
         TSRMLS_FETCH();
         zval_ptr_dtor(&prsrc->val);
       }
-      tsrm_set_interpreter_context(old_ctx);
+      INTERP_CTX_LEAVE();
       /* potentially shutdown ZE */
       sandwich_interp_dec_ref(prsrc->interp);
       free(prsrc);

Modified: PHP-Sandwich/trunk/lib/PHP/Interpreter.pm
==============================================================================
--- PHP-Sandwich/trunk/lib/PHP/Interpreter.pm	(original)
+++ PHP-Sandwich/trunk/lib/PHP/Interpreter.pm	Mon Aug  1 16:00:34 2005
@@ -129,8 +129,25 @@ script, or true. Throw an exception on f
   $php->include("somePhpFile.php");
 
 Calls the PHP construct include on the specified file (similar to Perl's
+C<use> keyword). Does not suppress duplicate usages.  Throws an exception on failure.
+
+=head3 include_once()
+
+  $php->include_once("somePhpFile.php");
+
+Calls the PHP construct include_once on the specified file (similar to Perl's
 C<use> keyword). Throws an exception on failure.
 
+=head3 is_multithreaded()
+
+  if($php->is_multithread) {
+    # I can instantiate a second independent interpreter
+  }
+
+A runtime check to determine if PHP is thread-safe - i.e. if more than one interpreter
+can be simultaneously instantiated.  If not, further calls to PHP::Interpreter->new() 
+will return the original PHP interpreter instance.
+
 =head3 call()
 
   $rv = $php->call(stroupper => $perlVar);

Modified: PHP-Sandwich/trunk/phpinterp.c
==============================================================================
--- PHP-Sandwich/trunk/phpinterp.c	(original)
+++ PHP-Sandwich/trunk/phpinterp.c	Mon Aug  1 16:00:34 2005
@@ -13,6 +13,11 @@
 #include "phpinterp.h"
 #include "phpfuncs.h"
 
+/* a true global in non-threaded servers */
+#ifndef ZTS
+static sandwich_per_interp *one_true_interp = NULL;
+#endif
+
 static pthread_key_t sandwich_per_thread_info_key;
 
 /* {{{ sandwich SAPI Details */
@@ -116,6 +121,7 @@ int sandwich_php_interpreter_create()
   if(ze_started) {
     return 0;
   }
+#ifdef ZTS
   pthread_key_create(&sandwich_per_thread_info_key, NULL);
 
   if (!tsrm_startup(128, 32, TSRM_ERROR_LEVEL_CORE, "/tmp/TSRM.log")) {
@@ -128,6 +134,7 @@ int sandwich_php_interpreter_create()
   core_globals = ts_resource(core_globals_id);
   sapi_globals = ts_resource(sapi_globals_id);
   tsrm_ls = ts_resource(0);
+#endif
 
   sandwich_sapi.php_ini_path_override = "/opt/ecelerity/3rdParty/lib/php.ini";
   sapi_startup(&sandwich_sapi);
@@ -144,49 +151,63 @@ sandwich_per_interp *sandwich_per_interp
 {
   /* if (!conf->eval_ok) return NULL; */
   sandwich_per_interp *info;
-  void *old_ctx = NULL;
+
+#ifndef ZTS
+  if(one_true_interp) return one_true_interp;
+#endif
 
   info = calloc(sizeof(*info), 1);
+  info->ref = 1;
 
-  if (!info->ctx) {
-    info->ctx = tsrm_new_interpreter_context();
-    info->ref = 1;
-    old_ctx = tsrm_set_interpreter_context(info->ctx);
-    {
-      TSRMLS_FETCH();
-      
-      zend_alter_ini_entry("register_argc_argv", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
-      zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
-      zend_alter_ini_entry("implicit_flush", 15, "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
-      zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
-  
-      SG(headers_sent) = 1;
-      SG(request_info).no_headers = 1;
-      SG(server_context) = info;
-      SG(options) = SAPI_OPTION_NO_CHDIR;
-      php_request_startup(TSRMLS_C);
-      PG(during_request_startup) = 0;
-      SandwichG(php) = info;
-      tsrm_set_interpreter_context(old_ctx);
-    }
+#ifdef ZTS
+  info->ctx = tsrm_new_interpreter_context();
+#else
+  one_true_interp = info;
+#endif
+
+  info->ref = 1;
+  INTERP_CTX_ENTER(info->ctx);
+  {
+    TSRMLS_FETCH();
+    
+    zend_alter_ini_entry("register_argc_argv", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+    zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+    zend_alter_ini_entry("implicit_flush", 15, "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+    zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+
+    SG(headers_sent) = 1;
+    SG(request_info).no_headers = 1;
+    SG(server_context) = info;
+    SG(options) = SAPI_OPTION_NO_CHDIR;
+    php_request_startup(TSRMLS_C);
+    PG(during_request_startup) = 0;
+    SandwichG(php) = info;
+    INTERP_CTX_LEAVE();
   }
+
   return info;
 }
 
 
 void sandwich_per_interp_shutdown(sandwich_per_interp *interp)
 {
-  void *old_ctx = NULL;
-  old_ctx = tsrm_set_interpreter_context(interp->ctx);
+#ifndef ZTS
+  if(one_true_interp == NULL) return;
+  else one_true_interp = NULL;
+#endif
+
+  INTERP_CTX_ENTER(interp->ctx);
   {
     TSRMLS_FETCH();
     php_request_shutdown(NULL);
-    tsrm_set_interpreter_context(NULL);
+    INTERP_CTX_LEAVE();
+#ifdef ZTS
     tsrm_free_interpreter_context(interp->ctx);
+#endif
     interp->ctx = NULL;
     free(interp);
   }
-  tsrm_set_interpreter_context(old_ctx);
+  INTERP_CTX_LEAVE();
 }
 
 int my_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC)
@@ -251,9 +272,8 @@ int my_eval_string(char *str, zval *retv
 SV *sandwich_eval(sandwich_per_interp *interp, char *code)
 {
   int rv = 0;
-  void *old_ctx = NULL;
   zval retval;
-  old_ctx = tsrm_set_interpreter_context(interp->ctx);
+  INTERP_CTX_ENTER(interp->ctx);
   {
     TSRMLS_FETCH();
     zend_try {
@@ -268,7 +288,7 @@ SV *sandwich_eval(sandwich_per_interp *i
     }
   }
 cleanup:
-  tsrm_set_interpreter_context(old_ctx);
+  INTERP_CTX_LEAVE();
   if(rv == -1) {
     croak("PHP Error in eval");
   } else {
@@ -279,21 +299,27 @@ cleanup:
   }
 }
 
-int sandwich_include(sandwich_per_interp *interp, char *file)
+int sandwich_include(sandwich_per_interp *interp, char *file, int once)
 {
   int rv = 0;
   void *old_ctx = NULL;
-  old_ctx = tsrm_set_interpreter_context(interp->ctx);
+  INTERP_CTX_ENTER(interp->ctx);
   {
     zend_file_handle file_handle;
     TSRMLS_FETCH();
     zend_try {
+        int dummy = 1;
         SG(request_info).path_translated = file;
         file_handle.type = ZEND_HANDLE_FILENAME;
         file_handle.handle.fd = 0;
         file_handle.filename = SG(request_info).path_translated;
         file_handle.opened_path = NULL;
         file_handle.free_filename = 0;
+        if(zend_hash_add(&EG(included_files), file, strlen(file)+1, (void *)&dummy, sizeof(int), NULL) != SUCCESS&& once) {
+          /* implicit success! */
+          rv = 0;
+          goto cleanup;
+        }
         rv = (php_execute_script(&file_handle TSRMLS_CC) == 1)?0:-1;
     } zend_catch {
       rv = -1;
@@ -302,7 +328,7 @@ int sandwich_include(sandwich_per_interp
     }
   }
 cleanup:
-  tsrm_set_interpreter_context(old_ctx);
+  INTERP_CTX_LEAVE();
   return rv;
 }
 

Modified: PHP-Sandwich/trunk/phpinterp.h
==============================================================================
--- PHP-Sandwich/trunk/phpinterp.h	(original)
+++ PHP-Sandwich/trunk/phpinterp.h	Mon Aug  1 16:00:34 2005
@@ -31,7 +31,7 @@ sandwich_per_interp *sandwich_per_interp
 void sandwhich_per_interp_shutdown(sandwich_per_interp *interp);
 
 SV *sandwich_eval(sandwich_per_interp *interp, char *code);
-int sandwich_include(sandwich_per_interp *interp, char *file);
+int sandwich_include(sandwich_per_interp *interp, char *file, int once);
 
 /* NOTE: caller must tsrm_set_interpreter_context and reset the old one */
 zval *sandwich_call_function(sandwich_per_interp *interp, zval *method, zval **params, zend_uint param_count);
@@ -42,4 +42,12 @@ zval *sandwich_call_function(sandwich_pe
 zval *SvZval(SV *sv TSRMLS_DC);
 SV *newSVzval(zval *param, sandwich_per_interp *interp);
 
+#ifdef ZTS
+#define INTERP_CTX_ENTER(ctx) void *old_ctx = tsrm_set_interpreter_context(ctx)
+#define INTERP_CTX_LEAVE()   tsrm_set_interpreter_context(old_ctx)
+#else
+#define INTERP_CTX_ENTER(ctx)
+#define INTERP_CTX_LEAVE()
+#endif
+
 #endif

Modified: PHP-Sandwich/trunk/t/7.t
==============================================================================
--- PHP-Sandwich/trunk/t/7.t	(original)
+++ PHP-Sandwich/trunk/t/7.t	Mon Aug  1 16:00:34 2005
@@ -14,10 +14,20 @@ ok my $a1 = $p->include($inc)->call('ide
   "Including a PHP file and executing a function off iti via call";
 
 ok my $p2 = new PHP::Interpreter(), "Create new PHP interpreter";
-ok $a1 = $p2->include($inc)->ident(1), 
-  "Including a PHP file and executing a function off iti via AUTOLOAD";
+if($p2->is_multithreaded) {
+  ok $a1 = $p2->include($inc)->ident(1), 
+    "Including a PHP file and executing a function off iti via AUTOLOAD";
+}
+else {
+  ok $a1 = $p2->include_once($inc)->ident(1), 
+    "Including a PHP file and executing a function off iti via AUTOLOAD";
+}
 
 ok my $p3 = new PHP::Interpreter(), "Create new PHP interpreter";
-ok $p3->include($inc), "Including a file";
+if($p3->is_multithreaded) {
+  ok $p3->include($inc), "Including a file";
+} else {
+  ok $p3->include_once($inc), "Including a file";
+}
 ok $p3->ident(1), 
   "... and executing a function off it via AUTOLOAD (2)";



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About