# PHP5 extensions: using existing functionnames as method names

- Thread: https://externals.io/message/25665
- Original archive: https://news-web.php.net/php.internals/25665
- Started by danhen@email.de on 2006-09-13T16:29:13+00:00
- Messages: 2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #25665 — danhen@email.de — 2006-09-13T16:29:13+00:00

URL: https://externals.io/message/25665#25665

>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

---

## #25666 — Sara Golemon — 2006-09-13T16:53:09+00:00

URL: https://externals.io/message/25665#25666 · In reply to: #25665

> 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;
 > }
 >
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
