# Internal class, read_property() and type == BP_VAR_W

- Thread: https://externals.io/message/19783
- Original archive: https://news-web.php.net/php.internals/19783
- Started by Michael Wallner on 2005-10-28T15:05:35+00:00
- Messages: 3
- 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

---

## #19783 — Michael Wallner — 2005-10-28T15:05:35+00:00

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

Hi,

I'm facing an issue I don't know how to overcome.

Short story:
I've an object which properties are connected to the internal struct
whith get_property() and write_property() object handlers.

Now if BP_VAR_W is used to access a property with read_prop() the
following works fine:

	// $this->body is a string
	$this->body{0} = 'X';

... but the following does nothing than producing a memleak:

	$body = &$this->body;
	$body = 'X';

Also, it seems impossible to connect *values* (longs or string lengths for instance) through 
that interface, because I cannot tell the zval that the value should point elsewhere...

Any advice very much appreciated :)
Do I have to disallow referenced writing access?

Long story (sorry):

static zval *_http_message_object_read_prop(zval *object, zval *member, int type TSRMLS_DC)
{
	getObjectEx(http_message_object, obj, object);
	http_message *msg = obj->message;
	zval *return_value;
#ifdef WONKY
	ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member)+1);
#else
	zend_property_info *pinfo = zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
	
	if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
		return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
	}
#endif

	if (type == BP_VAR_W) {
		return_value = &EG(uninitialized_zval);
		return_value->refcount = 1;
		return_value->is_ref = 1;
	} else {
		ALLOC_ZVAL(return_value);
		return_value->refcount = 0;
		return_value->is_ref = 0;
	}

#ifdef WONKY
	switch (h)
#else
	switch (pinfo->h)
#endif
	{
		case HTTP_MSG_PROPHASH_TYPE:
		case HTTP_MSG_CHILD_PROPHASH_TYPE:
			RETVAL_LONG(msg->type);
		break;

		case HTTP_MSG_PROPHASH_HTTP_VERSION:
		case HTTP_MSG_CHILD_PROPHASH_HTTP_VERSION:
			RETVAL_DOUBLE(msg->http.version);
		break;

		case HTTP_MSG_PROPHASH_BODY:
		case HTTP_MSG_CHILD_PROPHASH_BODY:
			phpstr_fix(PHPSTR(msg));
			RETVAL_PHPSTR(PHPSTR(msg), 0, !return_value->is_ref);
		break;

		case HTTP_MSG_PROPHASH_HEADERS:
		case HTTP_MSG_CHILD_PROPHASH_HEADERS:
			if (return_value->is_ref) {
				Z_TYPE_P(return_value) = IS_ARRAY;
				Z_ARRVAL_P(return_value) = &msg->hdrs;
			} else {
				array_init(return_value);
				zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
			}
		break;

		case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
		case HTTP_MSG_CHILD_PROPHASH_PARENT_MESSAGE:
			if (msg->parent) {
				RETVAL_OBJVAL(obj->parent);
			} else {
				RETVAL_NULL();
			}
		break;

		case HTTP_MSG_PROPHASH_REQUEST_METHOD:
		case HTTP_MSG_CHILD_PROPHASH_REQUEST_METHOD:
			if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.method) {
				RETVAL_STRING(msg->http.info.request.method, 1);
			} else {
				RETVAL_NULL();
			}
		break;

		case HTTP_MSG_PROPHASH_REQUEST_URI:
			if (HTTP_MSG_TYPE(REQUEST, msg) && msg->http.info.request.URI) {
				RETVAL_STRING(msg->http.info.request.URI, !return_value->is_ref);
			} else {
				RETVAL_NULL();
			}
		break;

		case HTTP_MSG_PROPHASH_RESPONSE_CODE:
		case HTTP_MSG_CHILD_PROPHASH_RESPONSE_CODE:
			if (HTTP_MSG_TYPE(RESPONSE, msg)) {
				RETVAL_LONG(msg->http.info.response.code);
			} else {
				RETVAL_NULL();
			}
		break;
		
		case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
		case HTTP_MSG_CHILD_PROPHASH_RESPONSE_STATUS:
			if (HTTP_MSG_TYPE(RESPONSE, msg) && msg->http.info.response.status) {
				RETVAL_STRING(msg->http.info.response.status, !return_value->is_ref);
			} else {
				RETVAL_NULL();
			}
		break;
		
		default:
#ifdef WONKY
			return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC);
#else
			RETVAL_NULL();
#endif
		break;
	}

	return return_value;
}

-- 
Michael - <mike(@)php.net> http://dev.iworks.at/ext-http/http-functions.html.gz

---

## #19784 — Dmitry Stogov — 2005-10-28T15:16:14+00:00

URL: https://externals.io/message/19783#19784 · In reply to: #19783

Hi Michael,

You should define get_property_ptr_ptr() callback to support such
assignments.

Thanks. Dmitry.

> -----Original Message-----
> From: Michael Wallner [mailto:mike@php.net] 
> Sent: Friday, October 28, 2005 7:06 PM
> To: internals@lists.php.net
> Subject: [PHP-DEV] Internal class, read_property() and type 
> == BP_VAR_W
> 
> 
> Hi,
> 
> I'm facing an issue I don't know how to overcome.
> 
> Short story:
> I've an object which properties are connected to the internal 
> struct whith get_property() and write_property() object handlers.
> 
> Now if BP_VAR_W is used to access a property with read_prop() 
> the following works fine:
> 
> 	// $this->body is a string
> 	$this->body{0} = 'X';
> 
> ... but the following does nothing than producing a memleak:
> 
> 	$body = &$this->body;
> 	$body = 'X';
> 
> Also, it seems impossible to connect *values* (longs or 
> string lengths for instance) through 
> that interface, because I cannot tell the zval that the value 
> should point elsewhere...
> 
> Any advice very much appreciated :)
> Do I have to disallow referenced writing access?
> 
> Long story (sorry):
> 
> static zval *_http_message_object_read_prop(zval *object, 
> zval *member, int type TSRMLS_DC) {
> 	getObjectEx(http_message_object, obj, object);
> 	http_message *msg = obj->message;
> 	zval *return_value;
> #ifdef WONKY
> 	ulong h = zend_get_hash_value(Z_STRVAL_P(member), 
> Z_STRLEN_P(member)+1); #else
> 	zend_property_info *pinfo = 
> zend_get_property_info(obj->zo.ce, member, 1 TSRMLS_CC);
> 	
> 	if (!pinfo || ACC_PROP_PUBLIC(pinfo->flags)) {
> 		return 
> zend_get_std_object_handlers()->read_property(object, member, 
> type TSRMLS_CC);
> 	}
> #endif
> 
> 	if (type == BP_VAR_W) {
> 		return_value = &EG(uninitialized_zval);
> 		return_value->refcount = 1;
> 		return_value->is_ref = 1;
> 	} else {
> 		ALLOC_ZVAL(return_value);
> 		return_value->refcount = 0;
> 		return_value->is_ref = 0;
> 	}
> 
> #ifdef WONKY
> 	switch (h)
> #else
> 	switch (pinfo->h)
> #endif
> 	{
> 		case HTTP_MSG_PROPHASH_TYPE:
> 		case HTTP_MSG_CHILD_PROPHASH_TYPE:
> 			RETVAL_LONG(msg->type);
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_HTTP_VERSION:
> 		case HTTP_MSG_CHILD_PROPHASH_HTTP_VERSION:
> 			RETVAL_DOUBLE(msg->http.version);
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_BODY:
> 		case HTTP_MSG_CHILD_PROPHASH_BODY:
> 			phpstr_fix(PHPSTR(msg));
> 			RETVAL_PHPSTR(PHPSTR(msg), 0, 
> !return_value->is_ref);
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_HEADERS:
> 		case HTTP_MSG_CHILD_PROPHASH_HEADERS:
> 			if (return_value->is_ref) {
> 				Z_TYPE_P(return_value) = IS_ARRAY;
> 				Z_ARRVAL_P(return_value) = &msg->hdrs;
> 			} else {
> 				array_init(return_value);
> 				
> zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, 
> (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
> 			}
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
> 		case HTTP_MSG_CHILD_PROPHASH_PARENT_MESSAGE:
> 			if (msg->parent) {
> 				RETVAL_OBJVAL(obj->parent);
> 			} else {
> 				RETVAL_NULL();
> 			}
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_REQUEST_METHOD:
> 		case HTTP_MSG_CHILD_PROPHASH_REQUEST_METHOD:
> 			if (HTTP_MSG_TYPE(REQUEST, msg) && 
> msg->http.info.request.method) {
> 				
> RETVAL_STRING(msg->http.info.request.method, 1);
> 			} else {
> 				RETVAL_NULL();
> 			}
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_REQUEST_URI:
> 			if (HTTP_MSG_TYPE(REQUEST, msg) && 
> msg->http.info.request.URI) {
> 				
> RETVAL_STRING(msg->http.info.request.URI, !return_value->is_ref);
> 			} else {
> 				RETVAL_NULL();
> 			}
> 		break;
> 
> 		case HTTP_MSG_PROPHASH_RESPONSE_CODE:
> 		case HTTP_MSG_CHILD_PROPHASH_RESPONSE_CODE:
> 			if (HTTP_MSG_TYPE(RESPONSE, msg)) {
> 				
> RETVAL_LONG(msg->http.info.response.code);
> 			} else {
> 				RETVAL_NULL();
> 			}
> 		break;
> 		
> 		case HTTP_MSG_PROPHASH_RESPONSE_STATUS:
> 		case HTTP_MSG_CHILD_PROPHASH_RESPONSE_STATUS:
> 			if (HTTP_MSG_TYPE(RESPONSE, msg) && 
> msg->http.info.response.status) {
> 				
> RETVAL_STRING(msg->http.info.response.status, !return_value->is_ref);
> 			} else {
> 				RETVAL_NULL();
> 			}
> 		break;
> 		
> 		default:
> #ifdef WONKY
> 			return 
> zend_get_std_object_handlers()->read_property(object, member, 
> type TSRMLS_CC); #else
> 			RETVAL_NULL();
> #endif
> 		break;
> 	}
> 
> 	return return_value;
> }
> 
> -- 
> Michael - <mike(@)php.net> 
> http://dev.iworks.at/ext-http/http-functions.html.gz

---

## #19785 — Michael Wallner — 2005-10-28T15:23:11+00:00

URL: https://externals.io/message/19783#19785 · In reply to: #19784

Hi Dmitry Stogov, you wrote:

> Hi Michael,
> 
> You should define get_property_ptr_ptr() callback to support such
> assignments.

Yeah, I looked at that, but what do I gain? get_property_ptr_ptr() will
be used for both described cases and instead of returning a zval* I'd have 
to return a zval**, but I could miss the obvious, and if that's the case, 
don't hesitate to drop me a quick pointer in the right direction!

Thanks a lot Dmitry,
-- 
Michael - <mike(@)php.net> http://dev.iworks.at/ext-http/http-functions.html.gz
