note 11945 deleted from phpdevel by felipe

From: Date: Tue, 22 Jul 2008 19:00:28 +0000
Subject: note 11945 deleted from phpdevel by felipe
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-142540@lists.php.net to get a copy of this message
Note Submitter: ale at tana dot it ---- PORTING CUSTOM C FUNCTION FROM PHP3 TO PHP4 And I mean just functions, not full-fledged php extension. I had a couple of them, working with PHP3, and I have ported them in PHP4. Here's how. 1) Makefile you should have CFLAGS something like -I/path/to/php/php-4.0.4pl1/Zend -I/path/to/php/php-4.0.4pl1 -I/path/to/php/php-4.0.4pl1/TSRM -I/path/to/php/php-4.0.4pl1/main -fPIC -DCOMPILE_DL=1 Only the include paths changed from PHP3. 2) Interface with PHP the php3_module_entry is now called zend_module_entry and has the same structure. The get-module function from which you used to return that value is not DLEXPORT, but ZEND_DLEXPORT. You may want to use the ZEND_GET_MODULE macro. For the function_entry, you may want to use the PHP_FE macros, but I found the PHP_NAMED_FUNCTION implied less changes. It goes as PHP_NAMED_FUNCTION(arrayret); /* declaration */ and /* in php3 was DLEXPORT void arrayret(INTERNAL_FUNCTION_PARAMETERS) */ PHP_NAMED_FUNCTION(arrayret) /* definition */ { pval **arg; char buf[512]; int ok = 0, i = -1; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) != SUCCESS || (*arg)->type != IS_STRING || (*arg)->value.str.val == NULL) { WRONG_PARAM_COUNT; } ... You've seen that *arg becomes **arg. The ..._ex() function will take the address of a pointer to pointer. ZEND_NUM_ARGS doesn't take any parameter (used to be ht). 3) Includes #include <php.h> #include <zend_globals.h> 4) Insert indirection One difficult point is the extra level of indirection that was introduced for reference counting. If you don't use complex data types your C function should now work. If you use, e.g., arrays, keep that level of indirection in mind: don't store a pval into an array, store a pointer. I had things as if (array_init(return_value) == SUCCESS) { ok = 1; for (i = 0; i < 100 && ok; ++i) /* insert 100 arrays in return value */ { pval entry; char buf[80]; if ((ok = array_init(&entry) == SUCCESS) != 0) { static char const entry_1[] = "one"; static char const entry_2[] = "two"; pval e1, e2; e1.value.str.val = e2.value.str.val = NULL; e1.type = e2.type = IS_STRING; e1.value.str.len = sprintf(buf, "%3d/%010u", i, i); e1.value.str.val = estrndup(buf, e1.value.str.len); ok = e1.value.str.val != NULL && _php3_hash_update(entry.value.ht, (char*)entry_1, sizeof entry_1, &e1, sizeof e1, NULL) == SUCCESS; if (ok) /* continue assigning a second string, etc... */ ... This stuff compiles due to some compatibilty macro definitions, but it doesn't work. The quickest way around is to insert an intermediate function. To make the code above work in PHP4 i preceded it with the following: #undef _php3_hash_update #define _php3_hash_update php4_hash_update_patch static int php4_hash_update_patch(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) { zval *tmp; int rtc; if (nDataSize != sizeof(zval)) /* check it was a pval */ return FAILURE; ALLOC_ZVAL(tmp); /* you need zend_globals.h for this */ *tmp = *(zval*)pData; tmp->is_ref = 0; tmp->refcount = 1; if ((rtc = zend_hash_update(ht, arKey, nKeyLength, (void*)&tmp, sizeof(zval*), pDest)) == FAILURE) { FREE_ZVAL(tmp); } return rtc; } Similar patches can be done for _php3_hash_next_index_insert, etcetera. You got the idea. I hope this may save some time to an occasional code porter, keep in mind I'm not a zend (sic) guru, I just crashed my head quite hardly before realizing what was going wrong. And 5) good luck!

« previous php.notes (#142540) next »