@@ -265,11 +265,23 @@ static zend_object* php_phongo_int64_clone_object(phongo_compat_object_handler_t
265265 return new_object ;
266266}
267267
268- static int php_phongo_int64_compare_objects (zval * o1 , zval * o2 )
268+ static bool php_phongo_int64_is_int64_object (zval * object )
269269{
270- php_phongo_int64_t * intern1 , * intern2 ;
270+ if (Z_TYPE_P (object ) != IS_OBJECT ) {
271+ return false;
272+ }
271273
272- ZEND_COMPARE_OBJECTS_FALLBACK (o1 , o2 );
274+ return Z_OBJ_P (object )-> ce == php_phongo_int64_ce ;
275+ }
276+
277+ static bool php_phongo_int64_is_long_or_double (zval * value )
278+ {
279+ return Z_TYPE_P (value ) == IS_LONG || Z_TYPE_P (value ) == IS_DOUBLE ;
280+ }
281+
282+ static int php_phongo_int64_compare_int64_objects (zval * o1 , zval * o2 )
283+ {
284+ php_phongo_int64_t * intern1 , * intern2 ;
273285
274286 intern1 = Z_INT64_OBJ_P (o1 );
275287 intern2 = Z_INT64_OBJ_P (o2 );
@@ -281,6 +293,105 @@ static int php_phongo_int64_compare_objects(zval* o1, zval* o2)
281293 return 0 ;
282294}
283295
296+ static int php_phongo_int64_compare_with_long_or_float (zval * object , zval * value )
297+ {
298+ php_phongo_int64_t * intern ;
299+ int64_t long_value ;
300+ double double_value ;
301+
302+ intern = Z_INT64_OBJ_P (object );
303+
304+ assert (php_phongo_int64_is_long_or_double (value ));
305+
306+ switch (Z_TYPE_P (value )) {
307+ case IS_LONG :
308+ long_value = Z_LVAL_P (value );
309+ if (intern -> integer != long_value ) {
310+ return intern -> integer < long_value ? -1 : 1 ;
311+ }
312+ break ;
313+
314+ case IS_DOUBLE :
315+ double_value = Z_DVAL_P (value );
316+ if (intern -> integer != double_value ) {
317+ return intern -> integer < double_value ? -1 : 1 ;
318+ }
319+ break ;
320+
321+ default :
322+ return 0 ;
323+ }
324+
325+ return 0 ;
326+ }
327+
328+ static int php_phongo_int64_compare_objects (zval * o1 , zval * o2 )
329+ {
330+ if (php_phongo_int64_is_int64_object (o1 ) && php_phongo_int64_is_int64_object (o2 )) {
331+ return php_phongo_int64_compare_int64_objects (o1 , o2 );
332+ }
333+
334+ if (php_phongo_int64_is_int64_object (o1 ) && php_phongo_int64_is_long_or_double (o2 )) {
335+ return php_phongo_int64_compare_with_long_or_float (o1 , o2 );
336+ }
337+
338+ if (php_phongo_int64_is_long_or_double (o1 ) && php_phongo_int64_is_int64_object (o2 )) {
339+ // Invert the result as we're flipping the values used for comparison
340+ return -1 * php_phongo_int64_compare_with_long_or_float (o2 , o1 );
341+ }
342+
343+ ZEND_COMPARE_OBJECTS_FALLBACK (o1 , o2 );
344+
345+ return 0 ;
346+ }
347+
348+ #if PHP_VERSION_ID < 80000
349+ static int php_phongo_int64_compare_with_other_type (zval * object , zval * value )
350+ {
351+ zval tmp_value ;
352+ zval result ;
353+ int ret ;
354+
355+ if (Z_OBJ_HT_P (object )-> cast_object (object , & tmp_value , ((Z_TYPE_P (value ) == IS_FALSE || Z_TYPE_P (value ) == IS_TRUE ) ? _IS_BOOL : Z_TYPE_P (value ))) == FAILURE ) {
356+ zval_ptr_dtor (& tmp_value );
357+ return 1 ;
358+ }
359+
360+ compare_function (& result , & tmp_value , value );
361+
362+ ret = Z_LVAL (result );
363+ zval_ptr_dtor (& tmp_value );
364+ zval_ptr_dtor (& result );
365+
366+ return ret ;
367+ }
368+
369+ static int php_phongo_int64_compare_zvals (zval * result , zval * op1 , zval * op2 )
370+ {
371+ /* Happy case: compare an int64 object with another object, long, or double */
372+ if ((php_phongo_int64_is_int64_object (op1 ) || php_phongo_int64_is_long_or_double (op1 )) && (php_phongo_int64_is_int64_object (op2 ) || php_phongo_int64_is_long_or_double (op2 ))) {
373+ ZVAL_LONG (result , php_phongo_int64_compare_objects (op1 , op2 ));
374+ return SUCCESS ;
375+ }
376+
377+ /* When comparing an int64 object with any other type, cast the int64 object to the desired type.
378+ * We know that if op1 is an object, op2 has to be the other type and vice versa. For op2 being
379+ * the object, we can again flip the values used for comparison and multiply the result with -1. */
380+
381+ if (php_phongo_int64_is_int64_object (op1 )) {
382+ ZVAL_LONG (result , php_phongo_int64_compare_with_other_type (op1 , op2 ));
383+ return SUCCESS ;
384+ }
385+
386+ if (php_phongo_int64_is_int64_object (op2 )) {
387+ ZVAL_LONG (result , -1 * php_phongo_int64_compare_with_other_type (op2 , op1 ));
388+ return SUCCESS ;
389+ }
390+
391+ return FAILURE ;
392+ }
393+ #endif
394+
284395static zend_result php_phongo_int64_cast_object (phongo_compat_object_handler_type * readobj , zval * retval , int type )
285396{
286397 php_phongo_int64_t * intern ;
@@ -563,6 +674,12 @@ void php_phongo_int64_init_ce(INIT_FUNC_ARGS)
563674 php_phongo_handler_int64 .offset = XtOffsetOf (php_phongo_int64_t , std );
564675 php_phongo_handler_int64 .cast_object = php_phongo_int64_cast_object ;
565676 php_phongo_handler_int64 .do_operation = php_phongo_int64_do_operation ;
677+
678+ /* On PHP 7.4, compare_objects is only used when comparing two objects.
679+ * Use the compare handler to compare an object with any other zval */
680+ #if PHP_VERSION_ID < 80000
681+ php_phongo_handler_int64 .compare = php_phongo_int64_compare_zvals ;
682+ #endif
566683}
567684
568685bool phongo_int64_new (zval * object , int64_t integer )
0 commit comments