Can you show some code? It will help to figure out
what's wrong.
Yes I can :)
stringclass.h
#ifndef PHP_STRINGCLASS_H
#define PHP_STRINGCLASS_H
extern zend_module_entry string_module_entry;
#define phpext_string_ptr &string_module_entry
#ifdef PHP_WIN32
#define PHP_STRING_API __declspec(dllexport)
#else
#define PHP_STRING_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(string);
PHP_MSHUTDOWN_FUNCTION(string);
PHP_RINIT_FUNCTION(string);
PHP_RSHUTDOWN_FUNCTION(string);
PHP_MINFO_FUNCTION(string);
#define STRING_METHOD(function_name)
ZEND_NAMED_FUNCTION(c_stringclass_##function_name)
#define STRING_ME(name, arg_info, flags)
ZEND_FENTRY(name, c_stringclass_ ##name, arg_info, flags)
#ifdef ZTS
#define string_G(v) TSRMG(string_globals_id, zend_string_globals *, v)
#else
#define string_G(v) (string_globals.v)
#endif
#endif
And stringclass.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "zend_compile.h"
#include "zend_interfaces.h"
#include "zend_exceptions.h"
#include "ext/standard/php_smart_str.h"
#include "ext/standard/php_string.h"
#include "php_stringclass.h"
static zend_class_entry *string_ce;
#ifdef COMPILE_DL_STRING
ZEND_GET_MODULE(string)
#endif
STRING_METHOD(__construct);
STRING_METHOD(length);
STRING_METHOD(toLower);
STRING_METHOD(toUpper);
STRING_METHOD(trim);
//STRING_METHOD(concat);
//STRING_METHOD(__toString);
//STRING_METHOD(replace);
//and so on
static
ZEND_BEGIN_ARG_INFO(arginfo_String___construct, 0)
ZEND_ARG_INFO(0, str) // parameter name
ZEND_END_ARG_INFO();
static zend_function_entry string_functions[] = {
STRING_ME(__construct, arginfo_String___construct, ZEND_ACC_PUBLIC)
STRING_ME(length, NULL, ZEND_ACC_PUBLIC)
STRING_ME(toLower, NULL, ZEND_ACC_PUBLIC)
STRING_ME(toUpper, NULL, ZEND_ACC_PUBLIC)
STRING_ME(trim, NULL, ZEND_ACC_PUBLIC)
//STRING_ME(concat, NULL, ZEND_ACC_PUBLIC)
//STRING_ME(__toString, NULL, ZEND_ACC_PUBLIC)
//STRING_ME(replace, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
static zend_object_handlers string_handlers;
typedef struct _string_object {
zend_object std;
char *data;
int len;
} string_object;
static void string_object_free_storage(void *object TSRMLS_DC)
{
string_object *intern = (string_object *)object;
zend_hash_destroy(intern->std.properties);
FREE_HASHTABLE(intern->std.properties);
if(intern->data) {
efree(intern->data);
}
efree(object);
}
static zend_object_value string_object_new_ex(zend_class_entry *class_type, string_object **obj TSRMLS_DC)
{
zend_object_value retval;
string_object *intern;
zval *tmp;
intern = emalloc(sizeof(string_object));
memset(intern, 0, sizeof(string_object));
intern->std.ce = class_type;
*obj = intern;
ALLOC_HASHTABLE(intern->std.properties);
zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) string_object_free_storage, `NULL` TSRMLS_CC);
retval.handlers = &string_handlers;
return retval;
}
static zend_object_value string_object_new(zend_class_entry *class_type TSRMLS_DC)
{
string_object *tmp;
return string_object_new_ex(class_type, &tmp TSRMLS_CC);
}
static zend_object_value string_object_clone(zval *zobject TSRMLS_DC)
{
zend_object_value new_obj_val;
zend_object *old_object;
zend_object *new_object;
zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
string_object *intern;
old_object = zend_objects_get_address(zobject TSRMLS_CC);
new_obj_val = string_object_new_ex(old_object->ce, &intern TSRMLS_CC);
new_object = &intern->std;
zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
return new_obj_val;
}
#if MBO_0
static zend_class_entry *string_get_ce(zval *object TSRMLS_DC)
{
return string_object;
}
#endif
#if PHP_MAJOR_VERSION
>= 6
#define EXTSRM TSRMLS_C
#else
#define EXTSRM
#endif
STRING_METHOD(__construct)
{
zval *object = getThis();
string_object *intern;
char *str;
long strlen;
php_set_error_handling(EH_THROW, zend_exception_get_default(EXTSRM) TSRMLS_CC);
intern = (string_object*)zend_object_store_get_object(object TSRMLS_CC);
if(ZEND_NUM_ARGS() > 0) {
if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &str, &strlen) == FAILURE) {
php_set_error_handling(EH_NORMAL, `NULL` TSRMLS_CC);
return;
}
intern->data = estrdup(str);
intern->len = strlen;
} else {
intern->data = "";
intern->len = 0;
}
php_set_error_handling(EH_NORMAL, `NULL` TSRMLS_CC);
}
STRING_METHOD(length)
{
zval *object = getThis();
string_object *intern;
intern = (string_object*)zend_object_store_get_object(object TSRMLS_CC);
RETVAL_LONG(intern->len);
}
STRING_METHOD(toLower)
{
zval *object = getThis();
string_object *intern;
char* ret;
intern = (string_object*)zend_object_store_get_object(object TSRMLS_CC);
ret = estrdup(intern->data);
if(intern->len > 0) {
php_strtolower(ret, intern->len);
}
RETVAL_STRING(ret, 1);
}
STRING_METHOD(toUpper)
{
zval *object = getThis();
string_object *intern;
char* ret;
intern = (string_object*)zend_object_store_get_object(object TSRMLS_CC);
ret = estrdup(intern->data);
if(intern->len > 0) {
php_strtoupper(ret, intern->len);
}
RETVAL_STRING(ret, 1);
}
STRING_METHOD(trim)
{
zval *object = getThis();
string_object *intern;
char *what;
int what_len;
int argc = ZEND_NUM_ARGS();
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &what, &what_len);
intern = (string_object*)zend_object_store_get_object(object TSRMLS_CC);
if(argc == 1) {
php_trim(intern->data, intern->len, what, what_len, return_value, 3 TSRMLS_CC);
} else {
php_trim(intern->data, intern->len, NULL, 0, return_value, 3 TSRMLS_CC);
}
}
zend_module_entry string_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"string",
string_functions,
PHP_MINIT(string),
PHP_MSHUTDOWN(string),
PHP_RINIT(string), /* Replace with NULL
if there's nothing to do at request start /
PHP_RSHUTDOWN(string), / Replace with NULL
if there's nothing to do at request end /
PHP_MINFO(string),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", / Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
PHP_MINIT_FUNCTION(string)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "String", string_functions);
string_ce = zend_register_internal_class(&ce TSRMLS_CC);
string_ce->create_object = string_object_new;
memcpy(&string_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
string_handlers.clone_obj = string_object_clone;
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(string)
{
return SUCCESS;
}
PHP_RINIT_FUNCTION(string)
{
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(string)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(string)
{
php_info_print_table_start();
php_info_print_table_header(2, "class String", "enabled");
php_info_print_table_end();
}
There are some more methods in there but the trim is present.
I left over the hlf of the methods out.
trim()
is definied by the normal string-functions. Thats why I think I get the warning.
But current()
, next()
and so on in ArrayIterator works also and they are definied as normal
array functions too.
Daniel
zend_module_entry string_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"string",
string_functions,
PHP_MINIT(string),
PHP_MSHUTDOWN(string),
PHP_RINIT(string), /* Replace withNULL
if there's nothing to do at
request start /
PHP_RSHUTDOWN(string), / Replace withNULL
if there's nothing to do
at request end /
PHP_MINFO(string),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", / Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};PHP_MINIT_FUNCTION(string)
{
zend_class_entry ce;INIT_CLASS_ENTRY(ce, "String", string_functions);
string_ce = zend_register_internal_class(&ce TSRMLS_CC);
string_ce->create_object = string_object_new;
memcpy(&string_handlers, zend_get_std_object_handlers(),
sizeof(zend_object_handlers));
string_handlers.clone_obj = string_object_clone;return SUCCESS;
}
Problem #1 (The one you actually wrote about)
You're registering your methods twice. Once in zend_module_entry as
global functions (the cause of your error), and again in
INIT_CLASS_ENTRY() (The right place to be doing it).
Solution: Change "string_functions" to "NULL" in zend_module_entry.
Now for the rest of my complaints (all minor points):
stringclass.h
Not a major problem, but this file naming will trip up static linking.
So long as this is only ever a shared module you don't have any worry of
course. But you might as well name it php_stringclass.h
#define STRING_METHOD(function_name)
ZEND_NAMED_FUNCTION(c_stringclass_##function_name)
#define STRING_ME(name, arg_info, flags)
ZEND_FENTRY(name, c_stringclass_ ##name, arg_info, flags)
There's nothing special about these macros except for the specific
function prefix you assign them. Any particular reason you're using them?
#ifdef ZTS
#define string_G(v) TSRMG(string_globals_id, zend_string_globals *, v)
#else
#define string_G(v) (string_globals.v)
#endif
It's common practice to use all uppercase for TSRM macros. Not really
an issue, but worth a mentiCONFORM!!!!! YOU MUST CONFORM!!!! :)
-Sara