Changes between Version 1 and Version 2 of Ticket #51525, comment 4
- Timestamp:
- 10/19/2020 02:35:40 PM (4 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Ticket #51525, comment 4
v1 v2 21 21 function apply_filters_typesafe( $tag, $arguments = array(), $value = null, ...$values ) { 22 22 23 if ( null === $value ) { 24 return apply_filters( $tag, $value, ...$values ); 23 if ( ! has_filter( $tag ) ) { 24 return $value; 25 } 26 27 static $types_map; 28 if (!$types_map) { 29 $types_map = [ 30 'boolean' => 'boolean', 31 'integer' => 'numeric', 32 'double' => 'numeric', 33 'string' => 'string', 34 'array' => 'array', 35 'resource' => 'resource', 36 'resource (closed)' => 'resource', 37 'NULL' => 'mixed', 38 ]; 25 39 } 26 40 27 41 $type = gettype( $value ); 28 $is_object = false; 29 switch ( $type ) { 30 case 'boolean': 31 $accepted_types = array( 'boolean' ); 32 break; 33 case 'integer': 34 case 'double': 35 $accepted_types = array( 'numeric' ); 36 break; 37 case 'string': 38 $accepted_types = array( 'string' ); 39 break; 40 case 'array': 41 $accepted_types = array( 'array' ); 42 break; 43 case 'resource': 44 case 'resource (closed)': 45 $accepted_types = array( 'resource' ); 46 break; 47 case 'object': 48 $is_object = true; 49 default: 50 $accepted_types = array(); 51 } 42 $is_object = is_object( $value ); 43 $accepted_types = isset( $types_map[ $type ] ) ? array( $types_map[ $type ] ) : array(); 52 44 45 // Do not calculate multiple times for same class. 46 static $classes_types = []; 53 47 // Skip calculation of accepted types if they are are explicitly passed. 54 48 if ( $is_object && empty ( $arguments['accepted_types'] ) ) { 55 49 $class = get_class( $value ); 56 $accepted_types = array( $class ); 57 $parent = get_parent_class( $class ); 58 while ( $parent ) { 59 $accepted_types[] = $parent; 60 $parent = get_parent_class( $parent ); 50 if ( isset( $classes_types[ $class ] ) ) { 51 $accepted_types = $classes_types[ $class ]; 52 } else { 53 $accepted_types = array( $class ); 54 $parent = get_parent_class( $class ); 55 while ( $parent ) { 56 $accepted_types[] = $parent; 57 $parent = get_parent_class( $parent ); 58 } 59 60 $accepted_types = array_merge( $accepted_types, class_implements( $class ) ); 61 61 } 62 62 63 $ accepted_types = array_merge( $accepted_types, class_implements( $class ) );63 $classes_types[ $class ] = $accepted_types; 64 64 } 65 65 66 // Can't use wp_parse_args because no external dependencies.67 66 $arguments = array_replace( 68 67 array( … … 77 76 $to_filter = $is_object ? clone $value : $value; 78 77 79 $filtered = apply_filters( $tag, $to_filter, ...$values ); 78 // `next_filter` function doesn't exist, but you get the point 79 $filter = next_filter( $tag ); 80 $filtered = $filter( $to_filter, ...$values ); 80 81 81 82 // 'mixed' is a valid PHP 8 pseudo-type so we support for consistency. 82 83 // That said, if mixed is fine then just use apply_filters. 83 84 if ( in_array( 'mixed', (array)$arguments['accepted_types'] ) ) { 84 return $filtered; 85 // `has_next_filter` function doesn't exist, but you get the point 86 return has_next_filter( $tag ) 87 ? apply_filters_typesafe( $tag, $arguments, $filtered, ...$values ) 88 : $filtered; 85 89 } 86 90 … … 90 94 } 91 95 92 if ( ( null === $filtered && !$arguments['nullable'] ) ) { 93 if ( $can_do_it_wrong ) { 94 _doing_it_wrong( 95 __FUNCTION__, 96 "Filters for $tag where not expected to return null.", 97 '5.6' 98 ); 96 if ( null === $filtered ) { 97 if ( !$arguments['nullable'] ) { 98 $filtered = $original; 99 100 if ( $can_do_it_wrong ) { 101 _doing_it_wrong( 102 __FUNCTION__, 103 "Filters for '$tag' where not expected to return null.", 104 '5.6' 105 ); 106 } 99 107 } 100 108 101 return $original; 109 // `has_next_filter` function doesn't exist, but you get the point 110 return has_next_filter( $tag ) 111 ? apply_filters_typesafe( $tag, $arguments, $filtered, ...$values ) 112 : $filtered; 102 113 } 103 114 … … 105 116 if ( ! $functions ) { 106 117 $functions = array( 118 'int' => 'is_int', 107 119 'integer' => 'is_int', 108 120 'double' => 'is_float', … … 122 134 } 123 135 124 foreach ( $arguments['accepted_types'] as $type ) {136 foreach ( (array)$arguments['accepted_types'] as $type ) { 125 137 if ( isset( $functions[ $type ] ) && call_user_func( $functions[ $type ], $filtered ) ) { 126 return $filtered; 138 // `has_next_filter` function doesn't exist, but you get the point 139 return has_next_filter( $tag ) 140 ? apply_filters_typesafe( $tag, $arguments, $filtered, ...$values ) 141 : $filtered; 127 142 } 128 143 129 144 if ( $is_object && is_string ( $type ) && is_a( $filtered, $type ) ) { 130 return $filtered; 145 // `has_next_filter` function doesn't exist, but you get the point 146 return has_next_filter( $tag ) 147 ? apply_filters_typesafe( $tag, $arguments, $filtered, ...$values ) 148 : $filtered; 131 149 } 132 150 } 133 151 134 152 if ( $can_do_it_wrong ) { 135 $expected = implode( ', ', $arguments['accepted_types'] );153 $expected = implode( "', '", $arguments['accepted_types'] ); 136 154 $actual = is_object( $filtered ) ? 'instance of ' . get_class($filtered) : gettype( $filtered ); 137 155 _doing_it_wrong( 138 156 __FUNCTION__, 139 "Filters for $tag where expected to return a value of one of types $expected. Got $actualinstead.",157 "Filters for '$tag' where expected to return a value of one of types: '$expected'. Got '$actual' instead.", 140 158 '5.6' 141 159 ); 142 160 } 143 144 return $original; 161 162 // `has_next_filter` function doesn't exist, but you get the point 163 return has_next_filter( $tag ) 164 ? apply_filters_typesafe( $tag, $arguments, $original, ...$values ) 165 : $original; 145 166 } 146 147 167 }}} 148 168