You don't need to bloat your code with a lookup array or a switch block.
Your input strings are predictably formatted (in order), so you can write a single regex pattern containing optional capture groups at each of the expected "units" in the input string. While using named capture groups provides some declarative benefit, it also bloats the regex pattern and the output array -- so I generally don't prefer to use them.
You will notice that there is a repeated format in the regex: (?:(\d+)unitLetter)?
. This makes modifying/extending the pattern very simple. All of those subpatterns make the targeted substring "optional" and the final letter in the subpattern distinguishes what unit of time is being isolated.
In this case, the match output structure goes:
[0]
: the full string match (we don't need it)
[1]
: yrs
[2]
: mths
[3]
: wks
[4]
: days
Code: (Demo)
$strings = ['27y5m6w2d', '1m1w', '2w3d', '999y3w', '27d', '5y2d'];
foreach ($strings as $string) {
preg_match('~(?:(\d+)y)?(?:(\d+)m)?(?:(\d+)w)?(?:(\d+)d)?~', $string, $m);
var_export([
'yrs' => $m[1] ?? '',
'mths' => $m[2] ?? '',
'wks' => $m[3] ?? '',
'days' => $m[4] ?? '',
]);
echo "\n---\n";
}
Output:
array (
'yrs' => '27',
'mths' => '5',
'wks' => '6',
'days' => '2',
)
---
array (
'yrs' => '',
'mths' => '1',
'wks' => '1',
'days' => '',
)
---
array (
'yrs' => '',
'mths' => '',
'wks' => '2',
'days' => '3',
)
---
array (
'yrs' => '999',
'mths' => '',
'wks' => '3',
'days' => '',
)
---
array (
'yrs' => '',
'mths' => '',
'wks' => '',
'days' => '27',
)
---
array (
'yrs' => '5',
'mths' => '',
'wks' => '',
'days' => '2',
)
---