@ -60,6 +60,21 @@ typedef struct {
zend_class_entry * message_ce ;
static zend_object_handlers message_object_handlers ;
static void Message_SuppressDefaultProperties ( zend_class_entry * class_type ) {
// We suppress all default properties, because all our properties are handled
// by our read_property handler.
//
// This also allows us to put our zend_object member at the beginning of our
// struct -- instead of putting it at the end with pointer fixups to access
// our own data, as recommended in the docs -- because Zend won't add any of
// its own storage directly after the zend_object if default_properties_count
// == 0.
//
// This is not officially supported, but since it simplifies the code, we'll
// do it for as long as it works in practice.
class_type - > default_properties_count = 0 ;
}
// PHP Object Handlers /////////////////////////////////////////////////////////
/**
@ -69,8 +84,7 @@ static zend_object_handlers message_object_handlers;
*/
static zend_object * Message_create ( zend_class_entry * class_type ) {
Message * intern = emalloc ( sizeof ( Message ) ) ;
// XXX(haberman): verify whether we actually want to take this route.
class_type - > default_properties_count = 0 ;
Message_SuppressDefaultProperties ( class_type ) ;
zend_object_std_init ( & intern - > std , class_type ) ;
intern - > std . handlers = & message_object_handlers ;
Arena_Init ( & intern - > arena ) ;
@ -114,14 +128,14 @@ static void Message_get(Message *intern, const upb_fielddef *f, zval *rv) {
if ( upb_fielddef_ismap ( f ) ) {
upb_mutmsgval msgval = upb_msg_mutable ( intern - > msg , f , arena ) ;
MapField_GetPhpWrapper ( rv , msgval . map , f , & intern - > arena ) ;
MapField_GetPhpWrapper ( rv , msgval . map , MapType_Get ( f ) , & intern - > arena ) ;
} else if ( upb_fielddef_isseq ( f ) ) {
upb_mutmsgval msgval = upb_msg_mutable ( intern - > msg , f , arena ) ;
RepeatedField_GetPhpWrapper ( rv , msgval . array , f , & intern - > arena ) ;
RepeatedField_GetPhpWrapper ( rv , msgval . array , TypeInfo_Get ( f ) ,
& intern - > arena ) ;
} else {
upb_msgval msgval = upb_msg_get ( intern - > msg , f ) ;
const Descriptor * subdesc = Descriptor_GetFromFieldDef ( f ) ;
Convert_UpbToPhp ( msgval , rv , upb_fielddef_type ( f ) , subdesc , & intern - > arena ) ;
Convert_UpbToPhp ( msgval , rv , TypeInfo_Get ( f ) , & intern - > arena ) ;
}
}
@ -130,16 +144,13 @@ static bool Message_set(Message *intern, const upb_fielddef *f, zval *val) {
upb_msgval msgval ;
if ( upb_fielddef_ismap ( f ) ) {
msgval . map_val = MapField_GetUpbMap ( val , f , arena ) ;
msgval . map_val = MapField_GetUpbMap ( val , MapType_Get ( f ) , arena ) ;
if ( ! msgval . map_val ) return false ;
} else if ( upb_fielddef_isseq ( f ) ) {
msgval . array_val = RepeatedField_GetUpbArray ( val , f , arena ) ;
msgval . array_val = RepeatedField_GetUpbArray ( val , TypeIn fo_Get ( f ) , arena ) ;
if ( ! msgval . array_val ) return false ;
} else {
upb_fieldtype_t type = upb_fielddef_type ( f ) ;
const Descriptor * subdesc = Descriptor_GetFromFieldDef ( f ) ;
bool ok = Convert_PhpToUpb ( val , & msgval , type , subdesc , arena ) ;
if ( ! ok ) return false ;
if ( ! Convert_PhpToUpb ( val , & msgval , TypeInfo_Get ( f ) , arena ) ) return false ;
}
upb_msg_set ( intern - > msg , f , msgval , arena ) ;
@ -149,11 +160,10 @@ static bool Message_set(Message *intern, const upb_fielddef *f, zval *val) {
static bool MessageEq ( const upb_msg * m1 , const upb_msg * m2 , const upb_msgdef * m ) ;
/**
* ValueEq ( ) ( )
* ValueEq ( )
*/
bool ValueEq ( upb_msgval val1 , upb_msgval val2 , upb_fieldtype_t type ,
const upb_msgdef * m ) {
switch ( type ) {
bool ValueEq ( upb_msgval val1 , upb_msgval val2 , TypeInfo type ) {
switch ( type . type ) {
case UPB_TYPE_BOOL :
return val1 . bool_val = = val2 . bool_val ;
case UPB_TYPE_INT32 :
@ -172,7 +182,7 @@ bool ValueEq(upb_msgval val1, upb_msgval val2, upb_fieldtype_t type,
return val1 . str_val . size = = val2 . str_val . size & &
memcmp ( val1 . str_val . data , val2 . str_val . data , val1 . str_val . size ) = = 0 ;
case UPB_TYPE_MESSAGE :
return MessageEq ( val1 . msg_val , val2 . msg_val , m ) ;
return MessageEq ( val1 . msg_val , val2 . msg_val , type . desc - > msgdef ) ;
default :
return false ;
}
@ -190,8 +200,6 @@ static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m)
const upb_fielddef * f = upb_msg_iter_field ( & i ) ;
upb_msgval val1 = upb_msg_get ( m1 , f ) ;
upb_msgval val2 = upb_msg_get ( m2 , f ) ;
upb_fieldtype_t type = upb_fielddef_type ( f ) ;
const upb_msgdef * sub_m = upb_fielddef_msgsubdef ( f ) ;
if ( upb_fielddef_haspresence ( f ) ) {
if ( upb_msg_has ( m1 , f ) ! = upb_msg_has ( m2 , f ) ) {
@ -201,18 +209,11 @@ static bool MessageEq(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m)
}
if ( upb_fielddef_ismap ( f ) ) {
const upb_fielddef * key_f = upb_msgdef_itof ( sub_m , 1 ) ;
const upb_fielddef * val_f = upb_msgdef_itof ( sub_m , 2 ) ;
upb_fieldtype_t key_type = upb_fielddef_type ( key_f ) ;
upb_fieldtype_t val_type = upb_fielddef_type ( val_f ) ;
const upb_msgdef * val_m = upb_fielddef_msgsubdef ( val_f ) ;
if ( ! MapEq ( val1 . map_val , val2 . map_val , key_type , val_type , val_m ) ) {
return false ;
}
if ( ! MapEq ( val1 . map_val , val2 . map_val , MapType_Get ( f ) ) ) return false ;
} else if ( upb_fielddef_isseq ( f ) ) {
if ( ! ArrayEq ( val1 . array_val , val2 . array_val , type , sub_m ) ) return false ;
if ( ! ArrayEq ( val1 . array_val , val2 . array_val , TypeInfo_Get ( f ) ) ) return false ;
} else {
if ( ! ValueEq ( val1 , val2 , type , sub_m ) ) return false ;
if ( ! ValueEq ( val1 , val2 , TypeInfo_Get ( f ) ) ) return false ;
}
}
@ -392,6 +393,25 @@ static zval *Message_get_property_ptr_ptr(PROTO_VAL *object, PROTO_STR *member,
return NULL ; // We do not have a properties table.
}
/**
* Message_clone_obj ( )
*
* Object handler for cloning an object in PHP . Called when PHP code does :
*
* $ msg2 = clone $ msg ;
*/
static zend_object * Message_clone_obj ( zval * object ) {
Message * intern = PROTO_MSG_P ( object ) ;
upb_msg * clone = upb_msg_new ( intern - > desc - > msgdef , Arena_Get ( & intern - > arena ) ) ;
// TODO: copy unknown fields?
// TODO: use official upb msg copy function
memcpy ( clone , intern - > msg , upb_msgdef_layout ( intern - > desc - > msgdef ) - > size ) ;
zval ret ;
Message_GetPhpWrapper ( & ret , intern - > desc , clone , & intern - > arena ) ;
return Z_OBJ_P ( & ret ) ;
}
/**
* Message_get_properties ( )
*
@ -415,8 +435,7 @@ void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg,
if ( ! ObjCache_Get ( msg , val ) ) {
Message * intern = emalloc ( sizeof ( Message ) ) ;
// XXX(haberman): verify whether we actually want to take this route.
desc - > class_entry - > default_properties_count = 0 ;
Message_SuppressDefaultProperties ( desc - > class_entry ) ;
zend_object_std_init ( & intern - > std , desc - > class_entry ) ;
intern - > std . handlers = & message_object_handlers ;
ZVAL_COPY ( & intern - > arena , arena ) ;
@ -521,15 +540,13 @@ bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init,
}
if ( upb_fielddef_ismap ( f ) ) {
msgval . map_val = MapField_GetUpbMap ( val , f , arena ) ;
msgval . map_val = MapField_GetUpbMap ( val , MapType_Get ( f ) , arena ) ;
if ( ! msgval . map_val ) return false ;
} else if ( upb_fielddef_isseq ( f ) ) {
msgval . array_val = RepeatedField_GetUpbArray ( val , f , arena ) ;
msgval . array_val = RepeatedField_GetUpbArray ( val , TypeIn fo_Get ( f ) , arena ) ;
if ( ! msgval . array_val ) return false ;
} else {
const Descriptor * desc = Descriptor_GetFromFieldDef ( f ) ;
upb_fieldtype_t type = upb_fielddef_type ( f ) ;
if ( ! Convert_PhpToUpbAutoWrap ( val , & msgval , type , desc , arena ) ) {
if ( ! Convert_PhpToUpbAutoWrap ( val , & msgval , TypeInfo_Get ( f ) , arena ) ) {
return false ;
}
}
@ -827,10 +844,9 @@ PHP_METHOD(Message, readWrapperValue) {
const upb_msg * wrapper = upb_msg_get ( intern - > msg , f ) . msg_val ;
const upb_msgdef * m = upb_fielddef_msgsubdef ( f ) ;
const upb_fielddef * val_f = upb_msgdef_itof ( m , 1 ) ;
const upb_fieldtype_t val_type = upb_fielddef_type ( val_f ) ;
upb_msgval msgval = upb_msg_get ( wrapper , val_f ) ;
zval ret ;
Convert_UpbToPhp ( msgval , & ret , val_type , NULL , & intern - > arena ) ;
Convert_UpbToPhp ( msgval , & ret , TypeInfo_Get ( val_f ) , & intern - > arena ) ;
RETURN_ZVAL ( & ret , 1 , 0 ) ;
} else {
RETURN_NULL ( ) ;
@ -883,10 +899,9 @@ PHP_METHOD(Message, writeWrapperValue) {
} else {
const upb_msgdef * m = upb_fielddef_msgsubdef ( f ) ;
const upb_fielddef * val_f = upb_msgdef_itof ( m , 1 ) ;
upb_fieldtype_t val_type = upb_fielddef_type ( val_f ) ;
upb_msg * wrapper ;
if ( ! Convert_PhpToUpb ( val , & msgval , val_type , NULL , arena ) ) {
if ( ! Convert_PhpToUpb ( val , & msgval , TypeInfo_Get ( val_f ) , arena ) ) {
return ; // Error is already set.
}
@ -996,9 +1011,7 @@ PHP_METHOD(Message, readOneof) {
{
upb_msgval msgval = upb_msg_get ( intern - > msg , f ) ;
const Descriptor * subdesc = Descriptor_GetFromFieldDef ( f ) ;
Convert_UpbToPhp ( msgval , & ret , upb_fielddef_type ( f ) , subdesc ,
& intern - > arena ) ;
Convert_UpbToPhp ( msgval , & ret , TypeInfo_Get ( f ) , & intern - > arena ) ;
}
RETURN_ZVAL ( & ret , 1 , 0 ) ;
@ -1039,8 +1052,7 @@ PHP_METHOD(Message, writeOneof) {
f = upb_msgdef_itof ( intern - > desc - > msgdef , field_num ) ;
if ( ! Convert_PhpToUpb ( val , & msgval , upb_fielddef_type ( f ) ,
Descriptor_GetFromFieldDef ( f ) , arena ) ) {
if ( ! Convert_PhpToUpb ( val , & msgval , TypeInfo_Get ( f ) , arena ) ) {
return ;
}
@ -1247,8 +1259,8 @@ PHP_METHOD(google_protobuf_Timestamp, fromDateTime) {
if ( call_user_function ( EG ( function_table ) , NULL , & function_name , & retval , 1 ,
datetime ) = = FAILURE | |
! Convert_PhpToUpb ( & retval , & timestamp_seconds , UPB_TYPE_INT64 , NULL ,
NULL ) ) {
! Convert_PhpToUpb ( & retval , & timestamp_seconds ,
TypeInfo_FromType ( UPB_TYPE_INT64 ) , NULL ) ) {
zend_error ( E_ERROR , " Cannot get timestamp from DateTime. " ) ;
return ;
}
@ -1273,8 +1285,8 @@ PHP_METHOD(google_protobuf_Timestamp, fromDateTime) {
if ( call_user_function ( EG ( function_table ) , NULL , & function_name , & retval , 2 ,
params ) = = FAILURE | |
! Convert_PhpToUpb ( & retval , & timestamp_nanos , UPB_TYPE_INT32 , NULL ,
NULL ) ) {
! Convert_PhpToUpb ( & retval , & timestamp_nanos ,
TypeInfo_FromType ( UPB_TYPE_INT32 ) , NULL ) ) {
zend_error ( E_ERROR , " Cannot format DateTime. " ) ;
return ;
}
@ -1360,6 +1372,7 @@ void Message_ModuleInit() {
h - > unset_property = Message_unset_property ;
h - > get_properties = Message_get_properties ;
h - > get_property_ptr_ptr = Message_get_property_ptr_ptr ;
h - > clone_obj = Message_clone_obj ;
WellKnownTypes_ModuleInit ( ) ; /* From wkt.inc. */
}