Commit ad7cce65273 for php.net

commit ad7cce652735253b881d5ea0ce5432eaa38e991c
Author: Tim Düsterhus <tim@bastelstu.be>
Date:   Tue May 19 10:47:00 2026 +0200

    zend_portability: Add `ZEND_CONTAINER_OF()` (#21903)

    * zend_portability: Add `ZEND_CONTAINER_OF()`

    * tree-wide: Use `ZEND_CONTAINER_OF()`

    Changes made with Coccinelle:

        @@
        type T_container;
        identifier member;
        expression e;
        @@

        - (T_container *)(((char *)(e)) - offsetof(T_container, member))
        + ZEND_CONTAINER_OF(e, T_container, member)

        @@
        type T_container;
        identifier member;
        expression e;
        typedef uintptr_t;
        @@

        - (T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
        + ZEND_CONTAINER_OF(e, T_container, member)

        @@
        type T_container;
        identifier member;
        expression e;
        @@

        - (const T_container *)(((char *)(e)) - offsetof(T_container, member))
        + ZEND_CONTAINER_OF(e, T_container, member)

        @@
        type T_container;
        identifier member;
        expression e;
        typedef uintptr_t;
        @@

        - (const T_container *)(((uintptr_t)(e)) - offsetof(T_container, member))
        + ZEND_CONTAINER_OF(e, T_container, member)

    * bcmath: Fix `get_bcmath_number_from_obj()` const-correctness

    A follow-up change to the new `ZEND_CONTAINER_OF()` macro will preserve the
    `const`-ness of the input pointer. By wrapping this macro inside a macro rather
    an an inline function we can preserve the `const`-ness across all layers.

    * zend_portability: Keep `const`-ness in `ZEND_CONTAINER_OF()`

    * zend_portability: Add C++ version to `ZEND_CONTAINER_OF()`

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index b17922f84c3..2daa75f798b 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -107,6 +107,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
     zend_fci_consumed_arg(), which allows moving a selected callback argument
     instead of copying it in zend_call_function(). Currently only a single
     consumed argument is supported.
+  . Added ZEND_CONTAINER_OF().

 ========================
 2. Build system changes
diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c
index 245c67c4544..cf907ca40bf 100644
--- a/Zend/Optimizer/zend_optimizer.c
+++ b/Zend/Optimizer/zend_optimizer.c
@@ -780,7 +780,7 @@ static bool zend_optimizer_ignore_class(zval *ce_zv, const zend_string *filename
 		if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) {
 			return true;
 		}
-		const Bucket *ce_bucket = (const Bucket*)((uintptr_t)ce_zv - offsetof(Bucket, val));
+		const Bucket *ce_bucket = ZEND_CONTAINER_OF(ce_zv, Bucket, val);
 		size_t offset = ce_bucket - EG(class_table)->arData;
 		if (offset < EG(persistent_classes_count)) {
 			return false;
@@ -801,7 +801,7 @@ static bool zend_optimizer_ignore_function(zval *fbc_zv, const zend_string *file
 			if (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE) {
 				return true;
 			}
-			const Bucket *fbc_bucket = (const Bucket*)((uintptr_t)fbc_zv - offsetof(Bucket, val));
+			const Bucket *fbc_bucket = ZEND_CONTAINER_OF(fbc_zv, Bucket, val);
 			size_t offset = fbc_bucket - EG(function_table)->arData;
 			if (offset < EG(persistent_functions_count)) {
 				return false;
diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c
index 9763dd34613..840d2dbe32e 100644
--- a/Zend/zend_closures.c
+++ b/Zend/zend_closures.c
@@ -830,7 +830,7 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en
 		/* wrap internal function handler to avoid memory leak */
 		if (UNEXPECTED(closure->func.internal_function.handler == zend_closure_internal_handler)) {
 			/* avoid infinity recursion, by taking handler from nested closure */
-			zend_closure *nested = (zend_closure*)((char*)func - offsetof(zend_closure, func));
+			zend_closure *nested = ZEND_CONTAINER_OF(func, zend_closure, func);
 			ZEND_ASSERT(nested->std.ce == zend_ce_closure);
 			closure->orig_internal_handler = nested->orig_internal_handler;
 		} else {
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index ee57e1dafb8..105f99d2417 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5175,7 +5175,7 @@ static zend_result zend_compile_func_array_map(znode *result, zend_ast_list *arg
 	opline->lineno = lineno;
 	opline->extended_value = (2 << 16) | IS_ARRAY;
 	const zval *fbc_zv = zend_hash_find(CG(function_table), lcname);
-	const Bucket *fbc_bucket = (const Bucket*)((uintptr_t)fbc_zv - offsetof(Bucket, val));
+	const Bucket *fbc_bucket = ZEND_CONTAINER_OF(fbc_zv, Bucket, val);
 	Z_EXTRA_P(CT_CONSTANT(opline->op1)) = fbc_bucket - CG(function_table)->arData;

 	/* Initialize the result array. */
@@ -5472,7 +5472,7 @@ static void zend_compile_call(znode *result, const zend_ast *ast, uint32_t type)

 		/* Store offset to function from symbol table in op2.extra. */
 		if (fbc->type == ZEND_INTERNAL_FUNCTION) {
-			const Bucket *fbc_bucket = (const Bucket*)((uintptr_t)fbc_zv - offsetof(Bucket, val));
+			const Bucket *fbc_bucket = ZEND_CONTAINER_OF(fbc_zv, Bucket, val);
 			Z_EXTRA_P(CT_CONSTANT(opline->op2)) = fbc_bucket - CG(function_table)->arData;
 		}

diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h
index 4e65ebf728a..6bffb886650 100644
--- a/Zend/zend_enum.h
+++ b/Zend/zend_enum.h
@@ -36,7 +36,7 @@ typedef struct zend_enum_obj {

 static inline zend_enum_obj *zend_enum_obj_from_obj(zend_object *zobj) {
 	ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_ENUM);
-	return (zend_enum_obj*)((char*)(zobj) - offsetof(zend_enum_obj, std));
+	return ZEND_CONTAINER_OF(zobj, zend_enum_obj, std);
 }

 void zend_enum_startup(void);
diff --git a/Zend/zend_fibers.h b/Zend/zend_fibers.h
index 7c0d30acab3..c72ffdc8f18 100644
--- a/Zend/zend_fibers.h
+++ b/Zend/zend_fibers.h
@@ -154,7 +154,7 @@ static zend_always_inline zend_fiber *zend_fiber_from_context(zend_fiber_context
 {
 	ZEND_ASSERT(context->kind == zend_ce_fiber && "Fiber context does not belong to a Zend fiber");

-	return (zend_fiber *)(((char *) context) - offsetof(zend_fiber, context));
+	return ZEND_CONTAINER_OF(context, zend_fiber, context);
 }

 static zend_always_inline zend_fiber_context *zend_fiber_get_context(zend_fiber *fiber)
diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h
index c5b5fe02929..ccad24682fd 100644
--- a/Zend/zend_portability.h
+++ b/Zend/zend_portability.h
@@ -387,6 +387,34 @@ char *alloca();
 #define ZEND_ELEMENT_COUNT(m)
 #endif

+#if __cplusplus
+extern "C++" {
+# include <cstddef>
+	template<typename T, typename M>
+	const T* zend_container_of(const M *ptr, size_t offset) {
+		return reinterpret_cast<const T*>(reinterpret_cast<const char*>(ptr) - offset);
+	}
+	template<typename T, typename M>
+	T* zend_container_of(M *ptr, size_t offset) {
+		return reinterpret_cast<T*>(reinterpret_cast<char*>(ptr) - offset);
+	}
+
+# define ZEND_CONTAINER_OF(ptr, Type, member) zend_container_of<Type, decltype(Type::member)>(ptr, offsetof(Type, member))
+}
+#elif __STDC_VERSION__ >= 202311L || ZEND_GCC_VERSION
+/* typeof is C23 or a GCC extension */
+# define ZEND_CONTAINER_OF(ptr, Type, member) \
+	_Generic( \
+		(ptr), \
+		const typeof(((Type*)0)->member) *: ((const Type*)((char*)(ptr) - offsetof(Type, member))), \
+		typeof(((Type*)0)->member) *: ((Type*)((char*)(ptr) - offsetof(Type, member))) \
+	)
+#else
+/* Define a variant that does not keep const-ness for older compilers. Mismatches
+ * are expected to be caught by CI running modern compilers. */
+# define ZEND_CONTAINER_OF(ptr, Type, member) ((Type*)((char*)(ptr) - offsetof(Type, member)))
+#endif
+
 #ifdef HAVE_BUILTIN_CONSTANT_P
 # define ZEND_CONST_COND(_condition, _default) \
 	(__builtin_constant_p(_condition) ? (_condition) : (_default))
diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c
index 066f43f6524..ad0308f44e2 100644
--- a/Zend/zend_weakrefs.c
+++ b/Zend/zend_weakrefs.c
@@ -58,10 +58,10 @@ static zend_class_entry *zend_ce_weakmap;
 static zend_object_handlers zend_weakref_handlers;
 static zend_object_handlers zend_weakmap_handlers;

-#define zend_weakref_from(o) ((zend_weakref*)(((char*) o) - offsetof(zend_weakref, std)))
+#define zend_weakref_from(o) (ZEND_CONTAINER_OF(o, zend_weakref, std))
 #define zend_weakref_fetch(z) zend_weakref_from(Z_OBJ_P(z))

-#define zend_weakmap_from(o) ((zend_weakmap*)(((char*) o) - offsetof(zend_weakmap, std)))
+#define zend_weakmap_from(o) (ZEND_CONTAINER_OF(o, zend_weakmap, std))
 #define zend_weakmap_fetch(z) zend_weakmap_from(Z_OBJ_P(z))

 static inline void zend_weakref_unref_single(
diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c
index 1c9e5ef2612..2e2d80f76f9 100644
--- a/ext/bcmath/bcmath.c
+++ b/ext/bcmath/bcmath.c
@@ -875,10 +875,7 @@ static int bcmath_number_compare(zval *op1, zval *op2);
 #endif
 #define CHECK_SCALE_OVERFLOW(scale) (scale > INT_MAX)

-static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj)
-{
-	return (bcmath_number_obj_t*)((char*)(obj) - offsetof(bcmath_number_obj_t, std));
-}
+#define get_bcmath_number_from_obj(obj) ZEND_CONTAINER_OF(obj, bcmath_number_obj_t, std)

 static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_zval(const zval *zv)
 {
@@ -1214,7 +1211,7 @@ static zend_result bc_num_from_obj_or_str_or_long(
 	bc_num *num, size_t *full_scale, const zend_object *obj, const zend_string *str, zend_long lval)
 {
 	if (obj) {
-		bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
+		const bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj);
 		*num = intern->num;
 		if (full_scale) {
 			*full_scale = intern->scale;
diff --git a/ext/curl/curl_private.h b/ext/curl/curl_private.h
index f097e1118f0..2e7b1cf41d3 100644
--- a/ext/curl/curl_private.h
+++ b/ext/curl/curl_private.h
@@ -152,13 +152,13 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source);
 zend_long php_curl_get_long(zval *zv);

 static inline php_curl *curl_from_obj(zend_object *obj) {
-	return (php_curl *)((char *)(obj) - offsetof(php_curl, std));
+	return ZEND_CONTAINER_OF(obj, php_curl, std);
 }

 #define Z_CURL_P(zv) curl_from_obj(Z_OBJ_P(zv))

 static inline php_curlsh *curl_share_from_obj(zend_object *obj) {
-	return (php_curlsh *)((char *)(obj) - offsetof(php_curlsh, std));
+	return ZEND_CONTAINER_OF(obj, php_curlsh, std);
 }

 #define Z_CURL_SHARE_P(zv) curl_share_from_obj(Z_OBJ_P(zv))
diff --git a/ext/curl/multi.c b/ext/curl/multi.c
index 2994c992a7a..36ea47a8bca 100644
--- a/ext/curl/multi.c
+++ b/ext/curl/multi.c
@@ -49,7 +49,7 @@
 zend_class_entry *curl_multi_ce;

 static inline php_curlm *curl_multi_from_obj(zend_object *obj) {
-	return (php_curlm *)((char *)(obj) - offsetof(php_curlm, std));
+	return ZEND_CONTAINER_OF(obj, php_curlm, std);
 }

 #define Z_CURL_MULTI_P(zv) curl_multi_from_obj(Z_OBJ_P(zv))
diff --git a/ext/date/php_date.h b/ext/date/php_date.h
index d480283643d..8d7dcd2a5ec 100644
--- a/ext/date/php_date.h
+++ b/ext/date/php_date.h
@@ -59,7 +59,7 @@ struct _php_date_obj {
 };

 static inline php_date_obj *php_date_obj_from_obj(zend_object *obj) {
-	return (php_date_obj*)((char*)(obj) - offsetof(php_date_obj, std));
+	return ZEND_CONTAINER_OF(obj, php_date_obj, std);
 }

 #define Z_PHPDATE_P(zv)  php_date_obj_from_obj(Z_OBJ_P((zv)))
@@ -76,7 +76,7 @@ struct _php_timezone_obj {
 };

 static inline php_timezone_obj *php_timezone_obj_from_obj(zend_object *obj) {
-	return (php_timezone_obj*)((char*)(obj) - offsetof(php_timezone_obj, std));
+	return ZEND_CONTAINER_OF(obj, php_timezone_obj, std);
 }

 #define Z_PHPTIMEZONE_P(zv)  php_timezone_obj_from_obj(Z_OBJ_P((zv)))
@@ -94,7 +94,7 @@ struct _php_interval_obj {
 };

 static inline php_interval_obj *php_interval_obj_from_obj(zend_object *obj) {
-	return (php_interval_obj*)((char*)(obj) - offsetof(php_interval_obj, std));
+	return ZEND_CONTAINER_OF(obj, php_interval_obj, std);
 }

 #define Z_PHPINTERVAL_P(zv)  php_interval_obj_from_obj(Z_OBJ_P((zv)))
@@ -113,7 +113,7 @@ struct _php_period_obj {
 };

 static inline php_period_obj *php_period_obj_from_obj(zend_object *obj) {
-	return (php_period_obj*)((char*)(obj) - offsetof(php_period_obj, std));
+	return ZEND_CONTAINER_OF(obj, php_period_obj, std);
 }

 #define Z_PHPPERIOD_P(zv)  php_period_obj_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/dba/dba.c b/ext/dba/dba.c
index 07123d0e301..29c560973b7 100644
--- a/ext/dba/dba.c
+++ b/ext/dba/dba.c
@@ -337,7 +337,7 @@ static zend_result dba_connection_cast_object(zend_object *obj, zval *result, in

 static inline dba_connection *dba_connection_from_obj(zend_object *obj)
 {
-	return (dba_connection *)((char *)(obj) - offsetof(dba_connection, std));
+	return ZEND_CONTAINER_OF(obj, dba_connection, std);
 }

 #define Z_DBA_CONNECTION_P(zv) dba_connection_from_obj(Z_OBJ_P(zv))
diff --git a/ext/dom/token_list.h b/ext/dom/token_list.h
index cf44f5016b8..7bddd6c9b46 100644
--- a/ext/dom/token_list.h
+++ b/ext/dom/token_list.h
@@ -30,7 +30,7 @@ static inline dom_token_list_object *php_dom_token_list_from_obj(zend_object *ob

 static inline dom_token_list_object *php_dom_token_list_from_dom_obj(dom_object *obj)
 {
-	return (dom_token_list_object *)((char *) obj - offsetof(dom_token_list_object, dom));
+	return ZEND_CONTAINER_OF(obj, dom_token_list_object, dom);
 }

 void dom_ordered_set_parser(HashTable *token_set, const char *position, bool to_lowercase);
diff --git a/ext/dom/xml_common.h b/ext/dom/xml_common.h
index c1e283b3f3d..42937cc3784 100644
--- a/ext/dom/xml_common.h
+++ b/ext/dom/xml_common.h
@@ -28,7 +28,7 @@ typedef struct _dom_object {
 } dom_object;

 static inline dom_object *php_dom_obj_from_obj(zend_object *obj) {
-	return (dom_object*)((char*)(obj) - offsetof(dom_object, std));
+	return ZEND_CONTAINER_OF(obj, dom_object, std);
 }

 #define Z_DOMOBJ_P(zv)  php_dom_obj_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c
index 2b9f1f0258d..bd9947b4ad1 100644
--- a/ext/dom/xpath.c
+++ b/ext/dom/xpath.c
@@ -207,7 +207,7 @@ zend_result dom_xpath_document_read(dom_object *obj, zval *retval)

 /* {{{ registerNodeNamespaces bool*/
 static inline dom_xpath_object *php_xpath_obj_from_dom_obj(dom_object *obj) {
-	return (dom_xpath_object*)((char*)(obj) - offsetof(dom_xpath_object, dom));
+	return ZEND_CONTAINER_OF(obj, dom_xpath_object, dom);
 }

 zend_result dom_xpath_register_node_ns_read(dom_object *obj, zval *retval)
diff --git a/ext/enchant/enchant.c b/ext/enchant/enchant.c
index 99c2cc74f6f..4a37908612b 100644
--- a/ext/enchant/enchant.c
+++ b/ext/enchant/enchant.c
@@ -49,7 +49,7 @@ zend_class_entry *enchant_broker_ce;
 static zend_object_handlers enchant_broker_handlers;

 static inline enchant_broker *enchant_broker_from_obj(zend_object *obj) {
-	return (enchant_broker *)((char *)(obj) - offsetof(enchant_broker, std));
+	return ZEND_CONTAINER_OF(obj, enchant_broker, std);
 }

 #define Z_ENCHANT_BROKER_P(zv) enchant_broker_from_obj(Z_OBJ_P(zv))
@@ -67,7 +67,7 @@ zend_class_entry *enchant_dict_ce;
 static zend_object_handlers enchant_dict_handlers;

 static inline enchant_dict *enchant_dict_from_obj(zend_object *obj) {
-	return (enchant_dict *)((char *)(obj) - offsetof(enchant_dict, std));
+	return ZEND_CONTAINER_OF(obj, enchant_dict, std);
 }

 #define Z_ENCHANT_DICT_P(zv) enchant_dict_from_obj(Z_OBJ_P(zv))
diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c
index 972529100d7..88126e9f612 100644
--- a/ext/fileinfo/fileinfo.c
+++ b/ext/fileinfo/fileinfo.c
@@ -44,7 +44,7 @@ typedef struct _finfo_object {
 } finfo_object;

 static inline finfo_object *php_finfo_fetch_object(zend_object *obj) {
-	return (finfo_object *)((char*)(obj) - offsetof(finfo_object, zo));
+	return ZEND_CONTAINER_OF(obj, finfo_object, zo);
 }

 #define Z_FINFO_P(zv) php_finfo_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index 343dd127378..92ab74fda57 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -150,7 +150,7 @@ static zend_function *php_gd_image_object_get_constructor(zend_object *object)

 static zend_always_inline php_gd_image_object* php_gd_exgdimage_from_zobj_p(zend_object* obj)
 {
-	return (php_gd_image_object *) ((char *) (obj) - offsetof(php_gd_image_object, std));
+	return ZEND_CONTAINER_OF(obj, php_gd_image_object, std);
 }

 /**
diff --git a/ext/gmp/php_gmp_int.h b/ext/gmp/php_gmp_int.h
index 98f0ddbc63b..01cf26eb3ed 100644
--- a/ext/gmp/php_gmp_int.h
+++ b/ext/gmp/php_gmp_int.h
@@ -36,7 +36,7 @@ typedef struct _gmp_object {
 } gmp_object;

 static inline gmp_object *php_gmp_object_from_zend_object(zend_object *zobj) {
-	return (gmp_object *)( ((char *)zobj) - offsetof(gmp_object, std) );
+	return ZEND_CONTAINER_OF(zobj, gmp_object, std);
 }

 PHP_GMP_API zend_class_entry *php_gmp_class_entry(void);
diff --git a/ext/intl/breakiterator/breakiterator_class.h b/ext/intl/breakiterator/breakiterator_class.h
index e7a80c0aaae..c18f9c67486 100644
--- a/ext/intl/breakiterator/breakiterator_class.h
+++ b/ext/intl/breakiterator/breakiterator_class.h
@@ -42,7 +42,7 @@ typedef struct {
 } BreakIterator_object;

 static inline BreakIterator_object *php_intl_breakiterator_fetch_object(zend_object *obj) {
-	return (BreakIterator_object *)((char*)(obj) - offsetof(BreakIterator_object, zo));
+	return ZEND_CONTAINER_OF(obj, BreakIterator_object, zo);
 }
 #define Z_INTL_BREAKITERATOR_P(zv) php_intl_breakiterator_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/calendar/calendar_class.h b/ext/intl/calendar/calendar_class.h
index b60777d7557..9f8040c8189 100644
--- a/ext/intl/calendar/calendar_class.h
+++ b/ext/intl/calendar/calendar_class.h
@@ -39,7 +39,7 @@ typedef struct {
 } Calendar_object;

 static inline Calendar_object *php_intl_calendar_fetch_object(zend_object *obj) {
-	return (Calendar_object *)((char*)(obj) - offsetof(Calendar_object, zo));
+	return ZEND_CONTAINER_OF(obj, Calendar_object, zo);
 }
 #define Z_INTL_CALENDAR_P(zv) php_intl_calendar_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/collator/collator_class.h b/ext/intl/collator/collator_class.h
index abbe4fe93eb..643291ab181 100644
--- a/ext/intl/collator/collator_class.h
+++ b/ext/intl/collator/collator_class.h
@@ -48,7 +48,7 @@ typedef struct {
 #define COLLATOR_ERROR_CODE_P(co) &(INTL_ERROR_CODE(COLLATOR_ERROR(co)))

 static inline Collator_object *php_intl_collator_fetch_object(zend_object *obj) {
-	return (Collator_object *)((char*)(obj) - offsetof(Collator_object, zo));
+	return ZEND_CONTAINER_OF(obj, Collator_object, zo);
 }
 #define Z_INTL_COLLATOR_P(zv) php_intl_collator_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/common/common_enum.h b/ext/intl/common/common_enum.h
index e32fc78a278..69633064ee9 100644
--- a/ext/intl/common/common_enum.h
+++ b/ext/intl/common/common_enum.h
@@ -53,7 +53,7 @@ typedef struct {


 static inline IntlIterator_object *php_intl_iterator_fetch_object(zend_object *obj) {
-	return (IntlIterator_object *)((char*)(obj) - offsetof(IntlIterator_object, zo));
+	return ZEND_CONTAINER_OF(obj, IntlIterator_object, zo);
 }
 #define Z_INTL_ITERATOR_P(zv) php_intl_iterator_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/dateformat/dateformat_class.h b/ext/intl/dateformat/dateformat_class.h
index ac3d5b4e291..dc94907e996 100644
--- a/ext/intl/dateformat/dateformat_class.h
+++ b/ext/intl/dateformat/dateformat_class.h
@@ -37,7 +37,7 @@ typedef struct {
 } IntlDateFormatter_object;

 static inline IntlDateFormatter_object *php_intl_dateformatter_fetch_object(zend_object *obj) {
-	return (IntlDateFormatter_object *)((char*)(obj) - offsetof(IntlDateFormatter_object, zo));
+	return ZEND_CONTAINER_OF(obj, IntlDateFormatter_object, zo);
 }
 #define Z_INTL_DATEFORMATTER_P(zv) php_intl_dateformatter_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/dateformat/datepatterngenerator_class.h b/ext/intl/dateformat/datepatterngenerator_class.h
index c6132a032f3..92739d39662 100644
--- a/ext/intl/dateformat/datepatterngenerator_class.h
+++ b/ext/intl/dateformat/datepatterngenerator_class.h
@@ -37,7 +37,7 @@ typedef struct {
 } IntlDatePatternGenerator_object;

 static inline IntlDatePatternGenerator_object *php_intl_datepatterngenerator_fetch_object(zend_object *obj) {
-	return (IntlDatePatternGenerator_object *)((char*)(obj) - offsetof(IntlDatePatternGenerator_object, zo));
+	return ZEND_CONTAINER_OF(obj, IntlDatePatternGenerator_object, zo);
 }
 #define Z_INTL_DATEPATTERNGENERATOR_P(zv) php_intl_datepatterngenerator_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/formatter/formatter_class.h b/ext/intl/formatter/formatter_class.h
index 47207b843bf..e7f4780bb3b 100644
--- a/ext/intl/formatter/formatter_class.h
+++ b/ext/intl/formatter/formatter_class.h
@@ -33,7 +33,7 @@ typedef struct {
 } NumberFormatter_object;

 static inline NumberFormatter_object *php_intl_number_format_fetch_object(zend_object *obj) {
-	return (NumberFormatter_object *)((char*)(obj) - offsetof(NumberFormatter_object, zo));
+	return ZEND_CONTAINER_OF(obj, NumberFormatter_object, zo);
 }
 #define Z_INTL_NUMBERFORMATTER_P(zv) php_intl_number_format_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h
index 6f8676193df..80b35f55b38 100644
--- a/ext/intl/listformatter/listformatter_class.h
+++ b/ext/intl/listformatter/listformatter_class.h
@@ -43,7 +43,7 @@ typedef struct {
 } ListFormatter_object;

 static inline ListFormatter_object *php_intl_listformatter_fetch_object(zend_object *obj) {
-    return (ListFormatter_object *)((char*)(obj) - offsetof(ListFormatter_object, zo));
+    return ZEND_CONTAINER_OF(obj, ListFormatter_object, zo);
 }
 #define Z_INTL_LISTFORMATTER_P(zv) php_intl_listformatter_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/msgformat/msgformat_class.h b/ext/intl/msgformat/msgformat_class.h
index d88b95b0ba7..a066b38e1d1 100644
--- a/ext/intl/msgformat/msgformat_class.h
+++ b/ext/intl/msgformat/msgformat_class.h
@@ -32,7 +32,7 @@ typedef struct {


 static inline MessageFormatter_object *php_intl_messageformatter_fetch_object(zend_object *obj) {
-	return (MessageFormatter_object *)((char*)(obj) - offsetof(MessageFormatter_object, zo));
+	return ZEND_CONTAINER_OF(obj, MessageFormatter_object, zo);
 }
 #define Z_INTL_MESSAGEFORMATTER_P(zv) php_intl_messageformatter_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/rangeformatter/rangeformatter_class.h b/ext/intl/rangeformatter/rangeformatter_class.h
index fefa7b6c35a..31b31d78428 100644
--- a/ext/intl/rangeformatter/rangeformatter_class.h
+++ b/ext/intl/rangeformatter/rangeformatter_class.h
@@ -37,7 +37,7 @@ typedef struct {
 } IntlNumberRangeFormatter_object;

 static inline IntlNumberRangeFormatter_object *php_intl_numberrangeformatter_fetch_object(zend_object *obj) {
-    return (IntlNumberRangeFormatter_object *)((char*)(obj) - offsetof(IntlNumberRangeFormatter_object, zo));
+    return ZEND_CONTAINER_OF(obj, IntlNumberRangeFormatter_object, zo);
 }

 #define Z_INTL_RANGEFORMATTER_P(zv) php_intl_numberrangeformatter_fetch_object(Z_OBJ_P(zv))
diff --git a/ext/intl/resourcebundle/resourcebundle_class.h b/ext/intl/resourcebundle/resourcebundle_class.h
index 2293df7b3e3..1ec2ac59222 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.h
+++ b/ext/intl/resourcebundle/resourcebundle_class.h
@@ -36,7 +36,7 @@ typedef struct {
 } ResourceBundle_object;

 static inline ResourceBundle_object *php_intl_resourcebundle_fetch_object(zend_object *obj) {
-	return (ResourceBundle_object *)((char*)(obj) - offsetof(ResourceBundle_object, zend));
+	return ZEND_CONTAINER_OF(obj, ResourceBundle_object, zend);
 }
 #define Z_INTL_RESOURCEBUNDLE_P(zv) php_intl_resourcebundle_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/spoofchecker/spoofchecker_class.h b/ext/intl/spoofchecker/spoofchecker_class.h
index d97ab8cff03..c3da53583b3 100644
--- a/ext/intl/spoofchecker/spoofchecker_class.h
+++ b/ext/intl/spoofchecker/spoofchecker_class.h
@@ -43,7 +43,7 @@ typedef struct {
 } Spoofchecker_object;

 static inline Spoofchecker_object *php_intl_spoofchecker_fetch_object(zend_object *obj) {
-	    return (Spoofchecker_object *)((char*)(obj) - offsetof(Spoofchecker_object, zo));
+	    return ZEND_CONTAINER_OF(obj, Spoofchecker_object, zo);
 }
 #define Z_INTL_SPOOFCHECKER_P(zv) php_intl_spoofchecker_fetch_object((Z_OBJ_P(zv)))

diff --git a/ext/intl/timezone/timezone_class.h b/ext/intl/timezone/timezone_class.h
index 70b3b5637f2..a8a05395b40 100644
--- a/ext/intl/timezone/timezone_class.h
+++ b/ext/intl/timezone/timezone_class.h
@@ -47,7 +47,7 @@ typedef struct {
 } TimeZone_object;

 static inline TimeZone_object *php_intl_timezone_fetch_object(zend_object *obj) {
-	return (TimeZone_object *)((char*)(obj) - offsetof(TimeZone_object, zo));
+	return ZEND_CONTAINER_OF(obj, TimeZone_object, zo);
 }
 #define Z_INTL_TIMEZONE_P(zv) php_intl_timezone_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/intl/transliterator/transliterator_class.h b/ext/intl/transliterator/transliterator_class.h
index 0268b8fa206..e94758996e5 100644
--- a/ext/intl/transliterator/transliterator_class.h
+++ b/ext/intl/transliterator/transliterator_class.h
@@ -39,7 +39,7 @@ typedef struct {
 } Transliterator_object;

 static inline Transliterator_object *php_intl_transliterator_fetch_object(zend_object *obj) {
-	return (Transliterator_object *)((char*)(obj) - offsetof(Transliterator_object, zo));
+	return ZEND_CONTAINER_OF(obj, Transliterator_object, zo);
 }
 #define Z_INTL_TRANSLITERATOR_P(zv) php_intl_transliterator_fetch_object(Z_OBJ_P(zv))

diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
index 89bf6c2258c..77322d2de59 100644
--- a/ext/ldap/ldap.c
+++ b/ext/ldap/ldap.c
@@ -101,7 +101,7 @@ ZEND_GET_MODULE(ldap)
 #endif

 static inline ldap_linkdata *ldap_link_from_obj(zend_object *obj) {
-	return (ldap_linkdata *)((char *)(obj) - offsetof(ldap_linkdata, std));
+	return ZEND_CONTAINER_OF(obj, ldap_linkdata, std);
 }

 #define Z_LDAP_LINK_P(zv) ldap_link_from_obj(Z_OBJ_P(zv))
@@ -148,7 +148,7 @@ static void ldap_link_free_obj(zend_object *obj)
 }

 static inline ldap_resultdata *ldap_result_from_obj(zend_object *obj) {
-	return (ldap_resultdata *)((char *)(obj) - offsetof(ldap_resultdata, std));
+	return ZEND_CONTAINER_OF(obj, ldap_resultdata, std);
 }

 #define Z_LDAP_RESULT_P(zv) ldap_result_from_obj(Z_OBJ_P(zv))
@@ -185,7 +185,7 @@ static void ldap_result_free_obj(zend_object *obj)
 }

 static inline ldap_result_entry *ldap_result_entry_from_obj(zend_object *obj) {
-	return (ldap_result_entry *)((char *)(obj) - offsetof(ldap_result_entry, std));
+	return ZEND_CONTAINER_OF(obj, ldap_result_entry, std);
 }

 #define Z_LDAP_RESULT_ENTRY_P(zv) ldap_result_entry_from_obj(Z_OBJ_P(zv))
diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h
index 7f43bf4edf5..bd16ab9e56c 100644
--- a/ext/mysqli/php_mysqli_structs.h
+++ b/ext/mysqli/php_mysqli_structs.h
@@ -62,7 +62,7 @@ typedef struct _mysqli_object {
 } mysqli_object; /* extends zend_object */

 static inline mysqli_object *php_mysqli_fetch_object(zend_object *obj) {
-	return (mysqli_object *)((char*)(obj) - offsetof(mysqli_object, zo));
+	return ZEND_CONTAINER_OF(obj, mysqli_object, zo);
 }

 #define Z_MYSQLI_P(zv) php_mysqli_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c
index c9f1b3f2e14..45d30f13a56 100644
--- a/ext/odbc/php_odbc.c
+++ b/ext/odbc/php_odbc.c
@@ -87,7 +87,7 @@ static void odbc_insert_new_result(odbc_connection *connection, zval *result)

 static inline odbc_link *odbc_link_from_obj(zend_object *obj)
 {
-	return (odbc_link *)((char *)(obj) - offsetof(odbc_link, std));
+	return ZEND_CONTAINER_OF(obj, odbc_link, std);
 }

 static int _close_pconn_with_res(zval *zv, void *p)
@@ -204,7 +204,7 @@ static void odbc_connection_free_obj(zend_object *obj)

 static inline odbc_result *odbc_result_from_obj(zend_object *obj)
 {
-	return (odbc_result *)((char *)(obj) - offsetof(odbc_result, std));
+	return ZEND_CONTAINER_OF(obj, odbc_result, std);
 }

 static zend_object *odbc_result_create_object(zend_class_entry *class_type)
diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h
index 72fd98745e1..ed47d885084 100644
--- a/ext/openssl/php_openssl.h
+++ b/ext/openssl/php_openssl.h
@@ -164,7 +164,7 @@ typedef struct _php_openssl_certificate_object {
 extern zend_class_entry *php_openssl_certificate_ce;

 static inline php_openssl_certificate_object *php_openssl_certificate_from_obj(zend_object *obj) {
-	return (php_openssl_certificate_object *)((char *)(obj) - offsetof(php_openssl_certificate_object, std));
+	return ZEND_CONTAINER_OF(obj, php_openssl_certificate_object, std);
 }

 #define Z_OPENSSL_CERTIFICATE_P(zv) php_openssl_certificate_from_obj(Z_OBJ_P(zv))
@@ -179,7 +179,7 @@ typedef struct _php_openssl_x509_request_object {
 } php_openssl_request_object;

 static inline php_openssl_request_object *php_openssl_request_from_obj(zend_object *obj) {
-	return (php_openssl_request_object *)((char *)(obj) - offsetof(php_openssl_request_object, std));
+	return ZEND_CONTAINER_OF(obj, php_openssl_request_object, std);
 }

 #define Z_OPENSSL_REQUEST_P(zv) php_openssl_request_from_obj(Z_OBJ_P(zv))
@@ -195,7 +195,7 @@ typedef struct _php_openssl_pkey_object {
 } php_openssl_pkey_object;

 static inline php_openssl_pkey_object *php_openssl_pkey_from_obj(zend_object *obj) {
-	return (php_openssl_pkey_object *)((char *)(obj) - offsetof(php_openssl_pkey_object, std));
+	return ZEND_CONTAINER_OF(obj, php_openssl_pkey_object, std);
 }

 #define Z_OPENSSL_PKEY_P(zv) php_openssl_pkey_from_obj(Z_OBJ_P(zv))
diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h
index 611b0ab4ccb..74449d56590 100644
--- a/ext/pdo/php_pdo_driver.h
+++ b/ext/pdo/php_pdo_driver.h
@@ -518,11 +518,11 @@ struct _pdo_dbh_object_t {
 };

 static inline pdo_dbh_t *php_pdo_dbh_fetch_inner(zend_object *obj) {
-	return (pdo_dbh_t *)(((pdo_dbh_object_t *)((char*)(obj) - offsetof(pdo_dbh_object_t, std)))->inner);
+	return (pdo_dbh_t *)((ZEND_CONTAINER_OF(obj, pdo_dbh_object_t, std))->inner);
 }

 static inline pdo_dbh_object_t *php_pdo_dbh_fetch_object(zend_object *obj) {
-	return (pdo_dbh_object_t *)((char*)(obj) - offsetof(pdo_dbh_object_t, std));
+	return ZEND_CONTAINER_OF(obj, pdo_dbh_object_t, std);
 }

 #define Z_PDO_DBH_P(zv) php_pdo_dbh_fetch_inner(Z_OBJ_P((zv)))
@@ -640,7 +640,7 @@ struct _pdo_stmt_t {


 static inline pdo_stmt_t *php_pdo_stmt_fetch_object(zend_object *obj) {
-	return (pdo_stmt_t *)((char*)(obj) - offsetof(pdo_stmt_t, std));
+	return ZEND_CONTAINER_OF(obj, pdo_stmt_t, std);
 }

 #define Z_PDO_STMT_P(zv) php_pdo_stmt_fetch_object(Z_OBJ_P((zv)))
@@ -651,7 +651,7 @@ struct _pdo_row_t {
 };

 static inline pdo_row_t *php_pdo_row_fetch_object(zend_object *obj) {
-	return (pdo_row_t *)((char*)(obj) - offsetof(pdo_row_t, std));
+	return ZEND_CONTAINER_OF(obj, pdo_row_t, std);
 }

 struct _pdo_scanner_t {
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 8cb022c79cd..8efd43ed3a8 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -152,7 +152,7 @@ static zend_class_entry *pgsql_link_ce, *pgsql_result_ce, *pgsql_lob_ce;
 static zend_object_handlers pgsql_link_object_handlers, pgsql_result_object_handlers, pgsql_lob_object_handlers;

 static inline pgsql_link_handle *pgsql_link_from_obj(zend_object *obj) {
-	return (pgsql_link_handle *)((char *)(obj) - offsetof(pgsql_link_handle, std));
+	return ZEND_CONTAINER_OF(obj, pgsql_link_handle, std);
 }

 #define Z_PGSQL_LINK_P(zv) pgsql_link_from_obj(Z_OBJ_P(zv))
@@ -208,7 +208,7 @@ static void pgsql_link_free_obj(zend_object *obj)
 }

 static inline pgsql_result_handle *pgsql_result_from_obj(zend_object *obj) {
-	return (pgsql_result_handle *)((char *)(obj) - offsetof(pgsql_result_handle, std));
+	return ZEND_CONTAINER_OF(obj, pgsql_result_handle, std);
 }

 #define Z_PGSQL_RESULT_P(zv) pgsql_result_from_obj(Z_OBJ_P(zv))
@@ -245,7 +245,7 @@ static void pgsql_result_free_obj(zend_object *obj)
 }

 static inline pgLofp *pgsql_lob_from_obj(zend_object *obj) {
-	return (pgLofp *)((char *)(obj) - offsetof(pgLofp, std));
+	return ZEND_CONTAINER_OF(obj, pgLofp, std);
 }

 #define Z_PGSQL_LOB_P(zv) pgsql_lob_from_obj(Z_OBJ_P(zv))
diff --git a/ext/random/php_random.h b/ext/random/php_random.h
index ccc06b1fba6..6e3df1317a4 100644
--- a/ext/random/php_random.h
+++ b/ext/random/php_random.h
@@ -126,11 +126,11 @@ extern PHPAPI zend_class_entry *random_ce_Random_Randomizer;
 extern PHPAPI zend_class_entry *random_ce_Random_IntervalBoundary;

 static inline php_random_engine *php_random_engine_from_obj(zend_object *object) {
-	return (php_random_engine *)((char *)(object) - offsetof(php_random_engine, std));
+	return ZEND_CONTAINER_OF(object, php_random_engine, std);
 }

 static inline php_random_randomizer *php_random_randomizer_from_obj(zend_object *object) {
-	return (php_random_randomizer *)((char *)(object) - offsetof(php_random_randomizer, std));
+	return ZEND_CONTAINER_OF(object, php_random_randomizer, std);
 }

 # define Z_RANDOM_ENGINE_P(zval) php_random_engine_from_obj(Z_OBJ_P(zval))
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index d15445d8d35..50bcf4cb79c 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -175,7 +175,7 @@ typedef struct {
 } reflection_object;

 static inline reflection_object *reflection_object_from_obj(zend_object *obj) {
-	return (reflection_object*)((char*)(obj) - offsetof(reflection_object, zo));
+	return ZEND_CONTAINER_OF(obj, reflection_object, zo);
 }

 #define Z_REFLECTION_P(zv)  reflection_object_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c
index bbf5b1b9ef8..8721e4333ce 100644
--- a/ext/shmop/shmop.c
+++ b/ext/shmop/shmop.c
@@ -70,7 +70,7 @@ static zend_object_handlers shmop_object_handlers;

 static inline php_shmop *shmop_from_obj(zend_object *obj)
 {
-	return (php_shmop *)((char *)(obj) - offsetof(php_shmop, std));
+	return ZEND_CONTAINER_OF(obj, php_shmop, std);
 }

 #define Z_SHMOP_P(zv) shmop_from_obj(Z_OBJ_P(zv))
diff --git a/ext/simplexml/php_simplexml_exports.h b/ext/simplexml/php_simplexml_exports.h
index 61cee427f73..8e07bbf19f2 100644
--- a/ext/simplexml/php_simplexml_exports.h
+++ b/ext/simplexml/php_simplexml_exports.h
@@ -36,7 +36,7 @@
 PHP_SXE_API zend_object *sxe_object_new(zend_class_entry *ce);

 static inline php_sxe_object *php_sxe_fetch_object(zend_object *obj) /* {{{ */ {
-	return (php_sxe_object *)((char*)(obj) - offsetof(php_sxe_object, zo));
+	return ZEND_CONTAINER_OF(obj, php_sxe_object, zo);
 }
 /* }}} */

diff --git a/ext/snmp/php_snmp.h b/ext/snmp/php_snmp.h
index 8e51a9430e9..40c5bebb0c0 100644
--- a/ext/snmp/php_snmp.h
+++ b/ext/snmp/php_snmp.h
@@ -57,7 +57,7 @@ typedef struct _php_snmp_object {
 } php_snmp_object;

 static inline php_snmp_object *php_snmp_fetch_object(zend_object *obj) {
-	return (php_snmp_object *)((char*)(obj) - offsetof(php_snmp_object, zo));
+	return ZEND_CONTAINER_OF(obj, php_snmp_object, zo);
 }

 #define Z_SNMP_P(zv) php_snmp_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h
index a2363c7a221..ce36dae11ae 100644
--- a/ext/soap/php_soap.h
+++ b/ext/soap/php_soap.h
@@ -260,7 +260,7 @@ typedef struct soap_url_object {

 static inline soap_url_object *soap_url_object_fetch(zend_object *obj)
 {
-	return (soap_url_object *) ((char *) obj - offsetof(soap_url_object, std));
+	return ZEND_CONTAINER_OF(obj, soap_url_object, std);
 }

 #define Z_SOAP_URL_P(zv) soap_url_object_fetch(Z_OBJ_P(zv))
diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 5cc87e7cc90..80602d47d7f 100644
--- a/ext/soap/soap.c
+++ b/ext/soap/soap.c
@@ -206,11 +206,11 @@ typedef struct {
 } soap_client_object;

 static inline soap_client_object *soap_client_object_fetch(zend_object *obj) {
-	return (soap_client_object *) ((char *) obj - offsetof(soap_client_object, std));
+	return ZEND_CONTAINER_OF(obj, soap_client_object, std);
 }

 static inline soap_server_object *soap_server_object_fetch(zend_object *obj) {
-	return (soap_server_object *) ((char *) obj - offsetof(soap_server_object, std));
+	return ZEND_CONTAINER_OF(obj, soap_server_object, std);
 }

 static zend_object *soap_client_object_create(zend_class_entry *ce)
@@ -288,7 +288,7 @@ static zend_result soap_url_cast_object(zend_object *obj, zval *result, int type

 static inline soap_sdl_object *soap_sdl_object_fetch(zend_object *obj)
 {
-	return (soap_sdl_object *) ((char *) obj - offsetof(soap_sdl_object, std));
+	return ZEND_CONTAINER_OF(obj, soap_sdl_object, std);
 }

 #define Z_SOAP_SDL_P(zv) soap_sdl_object_fetch(Z_OBJ_P(zv))
diff --git a/ext/sockets/php_sockets.h b/ext/sockets/php_sockets.h
index b7fe1e5af61..bc8d4617f7f 100644
--- a/ext/sockets/php_sockets.h
+++ b/ext/sockets/php_sockets.h
@@ -76,7 +76,7 @@ typedef struct {
 extern PHP_SOCKETS_API zend_class_entry *socket_ce;

 static inline php_socket *socket_from_obj(zend_object *obj) {
-	return (php_socket *)((char *)(obj) - offsetof(php_socket, std));
+	return ZEND_CONTAINER_OF(obj, php_socket, std);
 }

 #define Z_SOCKET_P(zv) socket_from_obj(Z_OBJ_P(zv))
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index 82ff0e80fcf..7b87a2a2f9b 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -181,7 +181,7 @@ zend_class_entry *address_info_ce;
 static zend_object_handlers address_info_object_handlers;

 static inline php_addrinfo *address_info_from_obj(zend_object *obj) {
-	return (php_addrinfo *)((char *)(obj) - offsetof(php_addrinfo, std));
+	return ZEND_CONTAINER_OF(obj, php_addrinfo, std);
 }

 #define Z_ADDRESS_INFO_P(zv) address_info_from_obj(Z_OBJ_P(zv))
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 1f9f87d3584..0105af77613 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -52,7 +52,7 @@ typedef struct _spl_array_object {
 } spl_array_object;

 static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_array_object*)((char*)(obj) - offsetof(spl_array_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_array_object, std);
 }
 /* }}} */

diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 47a0e38720b..95fc5e25be4 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -50,7 +50,7 @@ PHPAPI zend_class_entry *spl_ce_SplTempFileObject;

 /* Object helper */
 static inline spl_filesystem_object *spl_filesystem_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_filesystem_object*)((char*)(obj) - offsetof(spl_filesystem_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_filesystem_object, std);
 }
 /* }}} */

diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c
index be4f13cfcfc..39d2592b79a 100644
--- a/ext/spl/spl_dllist.c
+++ b/ext/spl/spl_dllist.c
@@ -86,7 +86,7 @@ struct _spl_dllist_it {
 };

 static inline spl_dllist_object *spl_dllist_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_dllist_object*)((char*)(obj) - offsetof(spl_dllist_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_dllist_object, std);
 }
 /* }}} */

diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c
index f865c101aed..cfaf209a56e 100644
--- a/ext/spl/spl_fixedarray.c
+++ b/ext/spl/spl_fixedarray.c
@@ -55,7 +55,7 @@ typedef struct _spl_fixedarray_it {

 static spl_fixedarray_object *spl_fixed_array_from_obj(zend_object *obj)
 {
-	return (spl_fixedarray_object*)((char*)(obj) - offsetof(spl_fixedarray_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_fixedarray_object, std);
 }

 #define Z_SPLFIXEDARRAY_P(zv)  spl_fixed_array_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c
index ffc9485bd79..cce07f4d91f 100644
--- a/ext/spl/spl_heap.c
+++ b/ext/spl/spl_heap.c
@@ -71,7 +71,7 @@ typedef struct _spl_pqueue_elem {
 } spl_pqueue_elem;

 static inline spl_heap_object *spl_heap_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_heap_object*)((char*)(obj) - offsetof(spl_heap_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_heap_object, std);
 }
 /* }}} */

diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index f96cc3dd9f9..bc4bfd75940 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -137,14 +137,14 @@ static zend_object_handlers spl_handlers_rec_it_it;
 static zend_object_handlers spl_handlers_dual_it;

 static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_recursive_it_object*)((char*)(obj) - offsetof(spl_recursive_it_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_recursive_it_object, std);
 }
 /* }}} */

 #define Z_SPLRECURSIVE_IT_P(zv)  spl_recursive_it_from_obj(Z_OBJ_P((zv)))

 static inline spl_dual_it_object *spl_dual_it_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_dual_it_object*)((char*)(obj) - offsetof(spl_dual_it_object, std));
+	return ZEND_CONTAINER_OF(obj, spl_dual_it_object, std);
 } /* }}} */

 #define Z_SPLDUAL_IT_P(zv)  spl_dual_it_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
index 2be720bbc50..7d565714afd 100644
--- a/ext/spl/spl_observer.c
+++ b/ext/spl/spl_observer.c
@@ -65,7 +65,7 @@ typedef struct _spl_SplObjectStorageElement {
 } spl_SplObjectStorageElement; /* }}} */

 static inline spl_SplObjectStorage *spl_object_storage_from_obj(zend_object *obj) /* {{{ */ {
-	return (spl_SplObjectStorage*)((char*)(obj) - offsetof(spl_SplObjectStorage, std));
+	return ZEND_CONTAINER_OF(obj, spl_SplObjectStorage, std);
 }
 /* }}} */

diff --git a/ext/sqlite3/php_sqlite3_structs.h b/ext/sqlite3/php_sqlite3_structs.h
index 942224ebf81..8012def8ea6 100644
--- a/ext/sqlite3/php_sqlite3_structs.h
+++ b/ext/sqlite3/php_sqlite3_structs.h
@@ -73,7 +73,7 @@ typedef struct _php_sqlite3_db_object  {
 } php_sqlite3_db_object;

 static inline php_sqlite3_db_object *php_sqlite3_db_from_obj(zend_object *obj) {
-	return (php_sqlite3_db_object*)((char*)(obj) - offsetof(php_sqlite3_db_object, zo));
+	return ZEND_CONTAINER_OF(obj, php_sqlite3_db_object, zo);
 }

 #define Z_SQLITE3_DB_P(zv)  php_sqlite3_db_from_obj(Z_OBJ_P((zv)))
@@ -102,7 +102,7 @@ struct _php_sqlite3_result_object  {
 };

 static inline php_sqlite3_result *php_sqlite3_result_from_obj(zend_object *obj) {
-	return (php_sqlite3_result*)((char*)(obj) - offsetof(php_sqlite3_result, zo));
+	return ZEND_CONTAINER_OF(obj, php_sqlite3_result, zo);
 }

 #define Z_SQLITE3_RESULT_P(zv)  php_sqlite3_result_from_obj(Z_OBJ_P((zv)))
@@ -120,7 +120,7 @@ struct _php_sqlite3_stmt_object  {
 };

 static inline php_sqlite3_stmt *php_sqlite3_stmt_from_obj(zend_object *obj) {
-	return (php_sqlite3_stmt*)((char*)(obj) - offsetof(php_sqlite3_stmt, zo));
+	return ZEND_CONTAINER_OF(obj, php_sqlite3_stmt, zo);
 }

 #define Z_SQLITE3_STMT_P(zv)  php_sqlite3_stmt_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c
index 533cc44cbec..16b4ffec50e 100644
--- a/ext/sysvmsg/sysvmsg.c
+++ b/ext/sysvmsg/sysvmsg.c
@@ -66,7 +66,7 @@ zend_class_entry *sysvmsg_queue_ce;
 static zend_object_handlers sysvmsg_queue_object_handlers;

 static inline sysvmsg_queue_t *sysvmsg_queue_from_obj(zend_object *obj) {
-	return (sysvmsg_queue_t *)((char *)(obj) - offsetof(sysvmsg_queue_t, std));
+	return ZEND_CONTAINER_OF(obj, sysvmsg_queue_t, std);
 }

 #define Z_SYSVMSG_QUEUE_P(zv) sysvmsg_queue_from_obj(Z_OBJ_P(zv))
diff --git a/ext/sysvsem/sysvsem.c b/ext/sysvsem/sysvsem.c
index 3672f1ac7af..9d3990d0bdc 100644
--- a/ext/sysvsem/sysvsem.c
+++ b/ext/sysvsem/sysvsem.c
@@ -83,7 +83,7 @@ zend_class_entry *sysvsem_ce;
 static zend_object_handlers sysvsem_object_handlers;

 static inline sysvsem_sem *sysvsem_from_obj(zend_object *obj) {
-	return (sysvsem_sem *)((char *)(obj) - offsetof(sysvsem_sem, std));
+	return ZEND_CONTAINER_OF(obj, sysvsem_sem, std);
 }

 #define Z_SYSVSEM_P(zv) sysvsem_from_obj(Z_OBJ_P(zv))
diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c
index d9082f269b6..96324e67c44 100644
--- a/ext/sysvshm/sysvshm.c
+++ b/ext/sysvshm/sysvshm.c
@@ -34,7 +34,7 @@ zend_class_entry *sysvshm_ce;
 static zend_object_handlers sysvshm_object_handlers;

 static inline sysvshm_shm *sysvshm_from_obj(zend_object *obj) {
-	return (sysvshm_shm *)((char *)(obj) - offsetof(sysvshm_shm, std));
+	return ZEND_CONTAINER_OF(obj, sysvshm_shm, std);
 }

 #define Z_SYSVSHM_P(zv) sysvshm_from_obj(Z_OBJ_P(zv))
diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c
index 7e695a6c422..cff4ad70341 100644
--- a/ext/tidy/tidy.c
+++ b/ext/tidy/tidy.c
@@ -105,7 +105,7 @@ struct _PHPTidyObj {
 };

 static inline PHPTidyObj *php_tidy_fetch_object(zend_object *obj) {
-	return (PHPTidyObj *)((char*)(obj) - offsetof(PHPTidyObj, std));
+	return ZEND_CONTAINER_OF(obj, PHPTidyObj, std);
 }

 #define Z_TIDY_P(zv) php_tidy_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h
index 888a3824545..65e9cff89a1 100644
--- a/ext/uri/php_uri_common.h
+++ b/ext/uri/php_uri_common.h
@@ -147,7 +147,7 @@ typedef struct php_uri_object {
 } php_uri_object;

 static inline php_uri_object *php_uri_object_from_obj(zend_object *object) {
-	return (php_uri_object*)((char*)(object) - offsetof(php_uri_object, std));
+	return ZEND_CONTAINER_OF(object, php_uri_object, std);
 }

 #define Z_URI_OBJECT_P(zv) php_uri_object_from_obj(Z_OBJ_P((zv)))
diff --git a/ext/xml/xml.c b/ext/xml/xml.c
index 1c08aef0e46..5bc502f2ef7 100644
--- a/ext/xml/xml.c
+++ b/ext/xml/xml.c
@@ -296,7 +296,7 @@ static void xml_xmlchar_zval(const XML_Char *s, int len, const XML_Char *encodin
 /* }}} */

 static inline xml_parser *xml_parser_from_obj(zend_object *obj) {
-	return (xml_parser *)((char *)(obj) - offsetof(xml_parser, std));
+	return ZEND_CONTAINER_OF(obj, xml_parser, std);
 }

 #define Z_XMLPARSER_P(zv) xml_parser_from_obj(Z_OBJ_P(zv))
diff --git a/ext/xmlreader/php_xmlreader.h b/ext/xmlreader/php_xmlreader.h
index 66585666a4f..161d5eddc0c 100644
--- a/ext/xmlreader/php_xmlreader.h
+++ b/ext/xmlreader/php_xmlreader.h
@@ -45,7 +45,7 @@ typedef struct _xmlreader_object {
 } xmlreader_object;

 static inline xmlreader_object *php_xmlreader_fetch_object(zend_object *obj) {
-	return (xmlreader_object *)((char*)(obj) - offsetof(xmlreader_object, std));
+	return ZEND_CONTAINER_OF(obj, xmlreader_object, std);
 }

 #define Z_XMLREADER_P(zv) php_xmlreader_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/xmlwriter/php_xmlwriter.h b/ext/xmlwriter/php_xmlwriter.h
index 39ca1c66b3e..7357d8af4da 100644
--- a/ext/xmlwriter/php_xmlwriter.h
+++ b/ext/xmlwriter/php_xmlwriter.h
@@ -38,7 +38,7 @@ typedef struct _ze_xmlwriter_object {
 } ze_xmlwriter_object;

 static inline ze_xmlwriter_object *php_xmlwriter_fetch_object(zend_object *obj) {
-	return (ze_xmlwriter_object *)((char*)(obj) - offsetof(ze_xmlwriter_object, std));
+	return ZEND_CONTAINER_OF(obj, ze_xmlwriter_object, std);
 }

 #define Z_XMLWRITER_P(zv) php_xmlwriter_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/xsl/php_xsl.h b/ext/xsl/php_xsl.h
index 2f2cf170d75..dd0eb7e370b 100644
--- a/ext/xsl/php_xsl.h
+++ b/ext/xsl/php_xsl.h
@@ -61,7 +61,7 @@ typedef struct xsl_object {
 } xsl_object;

 static inline xsl_object *php_xsl_fetch_object(zend_object *obj) {
-	return (xsl_object *)((char*)(obj) - offsetof(xsl_object, std));
+	return ZEND_CONTAINER_OF(obj, xsl_object, std);
 }

 #define Z_XSL_P(zv) php_xsl_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 48d28a8a4c3..52fe41eb18c 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -1114,7 +1114,7 @@ static zend_object *zend_test_class_new(zend_class_entry *class_type)

 static void zend_test_class_free_obj(zend_object *object)
 {
-	zend_test_object *intern = (zend_test_object*)((char*)object - offsetof(zend_test_object, std));
+	zend_test_object *intern = ZEND_CONTAINER_OF(object, zend_test_object, std);

 	if (intern->tmp_method) {
 		zend_internal_function *func = intern->tmp_method;
@@ -1129,7 +1129,7 @@ static void zend_test_class_free_obj(zend_object *object)

 static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key)
 {
-	zend_test_object *intern = (zend_test_object*)((char*)(*object) - offsetof(zend_test_object, std));
+	zend_test_object *intern = ZEND_CONTAINER_OF(*object, zend_test_object, std);

 	if (zend_string_equals_literal_ci(name, "test")) {
 		zend_internal_function *fptr;
diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h
index 6af1e3fb8b6..cdd72ba3636 100644
--- a/ext/zip/php_zip.h
+++ b/ext/zip/php_zip.h
@@ -82,7 +82,7 @@ typedef struct _ze_zip_object {
 } ze_zip_object;

 static inline ze_zip_object *php_zip_fetch_object(zend_object *obj) {
-	return (ze_zip_object *)((char*)(obj) - offsetof(ze_zip_object, zo));
+	return ZEND_CONTAINER_OF(obj, ze_zip_object, zo);
 }

 #define Z_ZIP_P(zv) php_zip_fetch_object(Z_OBJ_P((zv)))
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index a57796b2c66..50527ceffa3 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -48,7 +48,7 @@ zend_class_entry *inflate_context_ce;
 static zend_object_handlers inflate_context_object_handlers;

 static inline php_zlib_context *inflate_context_from_obj(zend_object *obj) {
-	return (php_zlib_context *)((char *)(obj) - offsetof(php_zlib_context, std));
+	return ZEND_CONTAINER_OF(obj, php_zlib_context, std);
 }

 #define Z_INFLATE_CONTEXT_P(zv) inflate_context_from_obj(Z_OBJ_P(zv))
@@ -86,7 +86,7 @@ zend_class_entry *deflate_context_ce;
 static zend_object_handlers deflate_context_object_handlers;

 static inline php_zlib_context *deflate_context_from_obj(zend_object *obj) {
-	return (php_zlib_context *)((char *)(obj) - offsetof(php_zlib_context, std));
+	return ZEND_CONTAINER_OF(obj, php_zlib_context, std);
 }

 #define Z_DEFLATE_CONTEXT_P(zv) deflate_context_from_obj(Z_OBJ_P(zv))