ObjectData* new_ZendObjectData_Instance(Class* cls) { TSRMLS_FETCH(); size_t nProps = cls->numDeclProperties(); size_t builtinObjSize = sizeof(c_ZendObjectData) - sizeof(ObjectData); size_t size = ObjectData::sizeForNProps(nProps) + builtinObjSize; auto obj = new (MM().objMallocLogged(size)) c_ZendObjectData(cls); zend_class_entry* ce = zend_hphp_class_to_class_entry(cls); auto create_func = ce->create_object; Class * current_class = cls; while (!create_func) { Class* parent = current_class->parent(); if (!parent) { break; } zend_class_entry* parent_ce = zend_hphp_class_to_class_entry(parent); create_func = parent_ce->create_object; current_class = parent; } zend_object_value ov; if (create_func) { ov = create_func(ce TSRMLS_CC); } else { zend_object *object; ov = zend_objects_new(&object, ce TSRMLS_CC); } obj->setHandle(ov.handle); if (UNLIKELY(cls->callsCustomInstanceInit())) { /* This must happen after the constructor finishes, because it can leak references to obj AND it can throw exceptions. If we have this in the ObjectData constructor, and it throws, obj will be partially destroyed (ie ~ObjectData will be called, resetting the vtable pointer) leaving dangling references to the object (eg in backtraces). */ obj->callCustomInstanceInit(); } return obj; }
void ZendObject::initZendObject(Class * cls) { TSRMLS_FETCH(); zend_class_entry* ce = zend_hphp_class_to_class_entry(cls); auto create_func = ce->create_object; Class * current_class = cls; while (!create_func) { Class* parent = current_class->parent(); if (!parent) { break; } zend_class_entry* parent_ce = zend_hphp_class_to_class_entry(parent); create_func = parent_ce->create_object; current_class = parent; } zend_object_value ov; if (create_func) { ov = create_func(ce TSRMLS_CC); } else { zend_object *object; ov = zend_objects_new(&object, ce TSRMLS_CC); } setHandle(ov.handle); }