Skip to content

Instantly share code, notes, and snippets.

@krakjoe
Last active December 15, 2015 18:38
Show Gist options
  • Save krakjoe/5304945 to your computer and use it in GitHub Desktop.
Save krakjoe/5304945 to your computer and use it in GitHub Desktop.
a (completely untested) unified php api, perhaps, just the "gist" ... its correct "enough" ...
/* +----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2013 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Sara Golemon (pollita@php.net) |
| Author: Joe Watkins (krakjoe@php.net) |
+----------------------------------------------------------------------+
*/
#ifndef PHP_API_H
#define PHP_API_H
#include "zend_execute.h"
#include "zend_API.h"
#include "zend_operators.h"
#include "zend_hash.h"
#include "zend_list.h"
/**
* All APIs in this file follow a general format:
*
* php_{$verb}{$modifier}_{$type}(zval *pzval, ...)
*
* $verb is one of:
* exists - Boolean check whether the array offset exists
* fetch - Retrieve the value at $pzval[$key]
* unset - Delete the named offset
*
* $modifier specifies what type of offset (key) is being used:
* <no modifer> - NULL terminated string variable, unknown length
* l - NULL terminated string variable, known length
* l_safe - String variable of known length, not necessarily NULL terminated
* n - Long (integer) offset
* c - NULL terminated string literal (e.g. "foo" rather than foo)
* z - zval* offset, type should be NULL, BOOL, LONG, DOUBLE, or STRING
*
* $type is specific to the "fetch" verb:
* <no type> - Fetch a zval* of any type
* bool - Fetch a zend_bool (converting as needed)
* long - Fetch a long (converting as needed)
* double - Fetch a double (converting as needed)
* string - Fetch a string (converting as needed, caller may need to free)
* array - Fetch an array (no conversion from other types)
* object - Fetch an object (no conversion, type spec optional)
* resource - Fetch a resource (no conversion, type spec mandatory)
*
* See the specific subsection for additional details
*/
/* isset($pzval[$key]) - Check for the existence of a key within an array
*
* zend_bool php_exists(zval *pzval, const char *key)
* zend_bool php_existsc(zval *pzval, const char *litstr)
* zend_bool php_existsl(zval *pzval, const char *key, int key_len)
* zend_bool php_existsl_safe(zval *pzval, const char *key, int key_len)
* zend_bool php_existsn(zval *pzval, ulong idx)
* zend_bool php_existsz(zval *pzval, zval *key)
*/
static inline
zend_bool php_api_exists(zval *pzval, const char *key, size_t keylen, zend_ulong idx, zend_bool safe TSRMLS_DC) {
zend_bool exists = 0;
char *ukey = NULL;
size_t ulen = keylen;
/* perform safety for key */
if (safe) {
ukey = estrndup(key);
} else ukey = (char*) key;
/* just an idea, but it might be nice in debug/some other mode
to warn the user of the unexpected */
#if defined(PHP_API_PEDANTIC)
/* we expect null terminated strings */
if (ulen != 0L &&
ukey[ulen] != '\0') {
/* free key if copied */
if (safe) {
efree(ukey);
}
/* copy key, null terminate and correct length */
ukey = emalloc(
ulen + 1);
memcpy(ukey, key, ulen);
ukey[++ulen] = '\0';
/* mark as safe to efree key */
safe = 1;
/* output a warning in this mode for developer */
}
/* anything else ?? */
#endif
switch (Z_TYPE(pzval)) {
case IS_ARRAY:
/* normal array_exists/isset */
if (ulen == 0L) {
exists = zend_hash_index_exists(Z_ARRVAL_P(pzval), idx);
} else exists = zend_hash_exists(Z_ARRVAL_P(pzval), ukey, ulen);
break;
case IS_OBJECT: {
/* attempt to use handlers where they are set */
zend_object_has_property_t handle = Z_OBJ_HT_P(pzval)->has_property;
if (handle) {
/* if we are using indexes then create a key from the index */
if (ulen == 0L) {
/* calculate length of key */
ulen = snprintf(
NULL, 0, "%lu", idx);
/* allocate and format key */
ukey = emalloc(ulen + 1);
if (ukey) {
snprintf(
ukey, ulen, "%lu", idx);
}
/* mark safe to efree key */
safe = 1;
}
/* perform call to handler */
exists = handle(pzval, ukey, ulen, 2 NULL TSRMLS_CC);
} else {
/* fallback on std properties */
HashTable *properties = Z_OBJPROP_P(pzval);
/* check so we can report the unexpected */
if (properties) {
if (ulen == 0L) {
exists = zend_hash_index_exists(properties, idx);
} else exists = zend_hash_exists(properties, ukey, ulen);
}
#if defined(PHP_API_PEDANTIC)
else {
/* do something, we do not expect null property tables */
}
#endif
}
}
}
/* perform safety cleanup */
if (safe) {
efree(ukey);
}
return exists;
}
#define php_exists(p, k)\
php_api_exists(p, k, strlen(k)+1, 0L, 0 TSRMLS_CC)
#define php_existsc(p, k)\
php_api_exists(p, k, sizeof(k), 0L, 0 TSRMLS_CC)
#define php_existsl(p, k, l)\
php_exists_api(p, k, l+1, 0L, 0 TSRMLS_CC)
#define php_existsl_safe(p, k, l, s)\
php_api_exists(p, k, l, 0L, s TSRMLS_CC)
#define php_existsn(p, k)\
php_api_exists(p, NULL, 0L, idx, 0 TSRMLS_CC)
static inline
zend_bool php_api_existsz(zval *pzval, zval *key TSRMLS_DC) {
switch (Z_TYPE_P(key)) {
case IS_NULL:
return php_api_exists(pzval, "", 1, 0L, 0 TSRMLS_CC);
case IS_BOOL:
case IS_LONG:
return php_api_exists(pzval, NULL, 0L, Z_LVAL_P(key), 0 TSRMLS_CC);
case IS_DOUBLE:
return php_api_exists(pzval, NULL, 0L, zend_dval_to_lval(Z_DVAL_P(key)), 0 TSRMLS_CC);
case IS_STRING:
return php_api_exists(pzval, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, 0L, 0 TSRMLS_CC);
default:
return 0;
}
}
#endif /* PHP_API_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment