@@ -87,11 +87,6 @@ ZEND_API void zend_observer_activate(void)
8787 current_observed_frame = NULL ;
8888}
8989
90- ZEND_API void zend_observer_deactivate (void )
91- {
92- // now empty and unused, but kept for ABI compatibility
93- }
94-
9590ZEND_API void zend_observer_shutdown (void )
9691{
9792 zend_llist_destroy (& zend_observers_fcall_list );
@@ -112,7 +107,7 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
112107 ZEND_ASSERT (RUN_TIME_CACHE (op_array ));
113108 zend_observer_fcall_begin_handler * begin_handlers = (zend_observer_fcall_begin_handler * )& ZEND_OBSERVER_DATA (op_array );
114109 zend_observer_fcall_end_handler * end_handlers = (zend_observer_fcall_end_handler * )begin_handlers + list -> count , * end_handlers_start = end_handlers ;
115-
110+
116111 * begin_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
117112 * end_handlers = ZEND_OBSERVER_NOT_OBSERVED ;
118113
@@ -127,7 +122,7 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
127122 * (end_handlers ++ ) = handlers .end ;
128123 }
129124 }
130-
125+
131126 // end handlers are executed in reverse order
132127 for (-- end_handlers ; end_handlers_start < end_handlers ; -- end_handlers , ++ end_handlers_start ) {
133128 zend_observer_fcall_end_handler tmp = * end_handlers ;
@@ -136,6 +131,65 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
136131 }
137132}
138133
134+ static bool zend_observer_remove_handler (void * * first_handler , void * old_handler ) {
135+ size_t registered_observers = zend_observers_fcall_list .count ;
136+
137+ void * * last_handler = first_handler + registered_observers - 1 ;
138+ for (void * * cur_handler = first_handler ; cur_handler <= last_handler ; ++ cur_handler ) {
139+ if (* cur_handler == old_handler ) {
140+ if (registered_observers == 1 || (cur_handler == first_handler && cur_handler [1 ] == NULL )) {
141+ * cur_handler = ZEND_OBSERVER_NOT_OBSERVED ;
142+ } else {
143+ if (cur_handler != last_handler ) {
144+ memmove (cur_handler , cur_handler + 1 , sizeof (cur_handler ) * (last_handler - cur_handler ));
145+ } else {
146+ * last_handler = NULL ;
147+ }
148+ }
149+ return true;
150+ }
151+ }
152+ return false;
153+ }
154+
155+ ZEND_API void zend_observer_add_begin_handler (zend_op_array * op_array , zend_observer_fcall_begin_handler begin ) {
156+ size_t registered_observers = zend_observers_fcall_list .count ;
157+ zend_observer_fcall_begin_handler * first_handler = (void * )& ZEND_OBSERVER_DATA (op_array ), * last_handler = first_handler + registered_observers - 1 ;
158+ if (* first_handler == ZEND_OBSERVER_NOT_OBSERVED ) {
159+ * first_handler = begin ;
160+ } else {
161+ for (zend_observer_fcall_begin_handler * cur_handler = first_handler + 1 ; cur_handler <= last_handler ; ++ cur_handler ) {
162+ if (* cur_handler == NULL ) {
163+ * cur_handler = begin ;
164+ return ;
165+ }
166+ }
167+ // there's no space for new handlers, then it's forbidden to call this function
168+ ZEND_UNREACHABLE ();
169+ }
170+ }
171+
172+ ZEND_API bool zend_observer_remove_begin_handler (zend_op_array * op_array , zend_observer_fcall_begin_handler begin ) {
173+ return zend_observer_remove_handler ((void * * )& ZEND_OBSERVER_DATA (op_array ), begin );
174+ }
175+
176+ ZEND_API void zend_observer_add_end_handler (zend_op_array * op_array , zend_observer_fcall_end_handler end ) {
177+ size_t registered_observers = zend_observers_fcall_list .count ;
178+ zend_observer_fcall_end_handler * end_handler = (zend_observer_fcall_end_handler * )& ZEND_OBSERVER_DATA (op_array ) + registered_observers ;
179+ // to allow to preserve the invariant that end handlers are in reverse order of begin handlers, push the new end handler in front
180+ if (* end_handler != ZEND_OBSERVER_NOT_OBSERVED ) {
181+ // there's no space for new handlers, then it's forbidden to call this function
182+ ZEND_ASSERT (end_handler [registered_observers - 1 ] == NULL );
183+ memmove (end_handler + 1 , end_handler , registered_observers - 1 );
184+ }
185+ * end_handler = end ;
186+ }
187+
188+ ZEND_API bool zend_observer_remove_end_handler (zend_op_array * op_array , zend_observer_fcall_end_handler end ) {
189+ size_t registered_observers = zend_observers_fcall_list .count ;
190+ return zend_observer_remove_handler ((void * * )& ZEND_OBSERVER_DATA (op_array ) + registered_observers , end );
191+ }
192+
139193static void ZEND_FASTCALL _zend_observe_fcall_begin (zend_execute_data * execute_data )
140194{
141195 if (!ZEND_OBSERVER_ENABLED ) {
@@ -205,8 +259,7 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_d
205259{
206260 zend_function * func = execute_data -> func ;
207261
208- if (!ZEND_OBSERVER_ENABLED
209- || !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
262+ if (!ZEND_OBSERVER_ENABLED || !ZEND_OBSERVABLE_FN (func -> common .fn_flags )) {
210263 return ;
211264 }
212265
0 commit comments