unsafe fn internal_new(val: Option<T>, ce: Option<&'static ClassEntry>) -> ZBox<Self> {
        let size = mem::size_of::<ZendClassObject<T>>();
        let meta = T::get_metadata();
        let ce = ptr::from_ref(ce.unwrap_or_else(|| meta.ce())).cast_mut();
        let obj = ext_php_rs_zend_object_alloc(size as _, ce).cast::<ZendClassObject<T>>();
        let obj = obj
            .as_mut()
            .expect("Failed to allocate for new Zend object");

        zend_object_std_init(&mut obj.std, ce);
        object_properties_init(&mut obj.std, ce);

        // SAFETY: `obj` is non-null and well aligned as it is a reference.
        // As the data in `obj.obj` is uninitialized, we don't want to drop
        // the data, but directly override it.
        ptr::write(&mut obj.obj, val);

        obj.std.handlers = meta.handlers();
        ZBox::from_raw(obj)
    }
Creates a new [`ZendObject`] of type `T`, storing the given (and
potentially uninitialized) `val` inside the object.

# Parameters

* `val` - Value to store inside the object. See safety section.
* `init` - Whether the given `val` was initialized.

# Safety

Providing an initialized variant of [`MaybeUninit<T>`] is safe.

Providing an uninitialized variant of [`MaybeUninit<T>`] is unsafe. As
the object is uninitialized, the caller must ensure the following
until the internal object is initialized:

* The object is never dereferenced to `T`.
* The [`Clone`] implementation is never called.
* The [`Debug`] implementation is never called.

If any of these conditions are not met while not initialized, the
corresponding function will panic. Converting the object into its
inner with the [`into_raw`] function is valid, however. You can
initialize the object with the [`initialize`] function.

[`into_raw`]: #method.into_raw
[`initialize`]: #method.initialize

# Panics

Panics if memory was unable to be allocated for the new object.
src/types/class_object.rs