phparrayssubstringfilteringpartial-matches

Filter flat array by checking if key contains one of several qualifying substrings


I have an array made up of data provided by a WordPress plugin, which looks something like this:

array(
    [label] => Evening, 
    [hour] => 15,
    [minute] => 00, 
    [add_time] => enabled, 
    [zlzkrrwlwchehhtvdnmq_add_date] => 29 November 2022, 
    [zlzkrrwlwchehhtvdnmq_zoom_id] => null,
    [zlzkrrwlwchehhtvdnmq_stock] => null,
    [sfujorleiwijcczciess_add_date] => 30 November 2022
)

I would like to keep all the key-value pairs in the array in which the key contains either 'add_date', 'hour', or 'minute', and discard the rest.

Keeping all the keys containing 'add_date' works fine.

if(strpos($key, 'add_date') == 0) {
           unset($datesresult[$key]);
        }
    }

This gives me an array containing only key-value pairs related to the date:

array(
    [zlzkrrwlwchehhtvdnmq_add_date] => 29 November 2022, 
    [sfujorleiwijcczciess_add_date] => 30 November 2022
)

However, when I try to match more than one condition using the OR operator, it doesn't work. This:

if(strpos($key, 'add_date') == 0 OR strpos($key, 'hour') == 0 OR strpos($key, 'minute') == 0) {
           unset($datesresult[$key]);
        }
    }

...gives me a completely blank array.

I've also tried various double negatives, like

if(!(strpos($key, 'add_date') == true || strpos($key, 'hour') == true || strpos($key, 'minute') == true)){
           unset($datesresult[$key]);
           }
       }

..but I get the same result.

I'm certain I'm doing something wrong here, either in syntax (I can't seem to find any examples of chaining operators in conditional statements like this in the PHP docs?) or in my understanding of true/false, but I can't work out what - my PHP is incredibly rusty after a long time away from coding.

Any wisdom would be much appreciated!


Solution

  • Declare a whitelist array of all permitted substrings, then filter your array by comparing keys against the whitelisted strings.

    Use a conditional early return in your foreach() for best efficiency.

    Code: (Demo)

    $whitelist = ['add_date', 'hour', 'minute'];
    
    var_export(
        array_filter(
            $array,
            function($k) use($whitelist) {
                foreach ($whitelist as $string) {
                    if (str_contains($k, $string)) {
                        return true;
                    }
                }
                return false;
            },
            ARRAY_FILTER_USE_KEY
        )
    );
    

    Using a whitelist array afford easier maintainability of code. Otherwise you'll need to copy values and function calls when you want to extend your filter logic.

    If you want to hardcode it, then it can look like this: (Demo)

    var_export(
        array_filter(
            $array,
            fn($k) => str_contains($k, 'add_date') || str_contains($k, 'hour') || str_contains($k, 'minute'),
            ARRAY_FILTER_USE_KEY
        )
    );
    

    Or if you are comfortable with regular expressions and don't mind hard-coding a pattern into your application, you can filter by an expression that using alternation and an end-of-string anchor. (Demo)

    var_export(
        array_filter(
            $array,
            fn($k) => preg_match('/(?:add_date|hour|minute)$/', $k),
            ARRAY_FILTER_USE_KEY
        )
    );