33namespace ZxcvbnPhp ;
44
55use ZxcvbnPhp \Matchers \Match ;
6+ use ZxcvbnPhp \Matchers \MatchInterface ;
67
78class Matcher
89{
10+ private const DEFAULT_MATCHERS = [
11+ Matchers \DateMatch::class,
12+ Matchers \DictionaryMatch::class,
13+ Matchers \ReverseDictionaryMatch::class,
14+ Matchers \L33tMatch::class,
15+ Matchers \RepeatMatch::class,
16+ Matchers \SequenceMatch::class,
17+ Matchers \SpatialMatch::class,
18+ Matchers \YearMatch::class,
19+ ];
20+
21+ private $ additionalMatchers = [];
22+
923 /**
1024 * Get matches for a password.
1125 *
@@ -24,14 +38,27 @@ public function getMatches($password, array $userInputs = [])
2438 foreach ($ this ->getMatchers () as $ matcher ) {
2539 $ matched = $ matcher ::match ($ password , $ userInputs );
2640 if (is_array ($ matched ) && !empty ($ matched )) {
27- $ matches = array_merge ( $ matches , $ matched) ;
41+ $ matches[] = $ matched ;
2842 }
2943 }
3044
45+ $ matches = array_merge ([], ...$ matches );
3146 self ::usortStable ($ matches , [$ this , 'compareMatches ' ]);
47+
3248 return $ matches ;
3349 }
3450
51+ public function addMatcher (string $ className )
52+ {
53+ if (!is_a ($ className , MatchInterface::class, true )) {
54+ throw new \InvalidArgumentException (sprintf ('Matcher class must implement %s ' , MatchInterface::class));
55+ }
56+
57+ $ this ->additionalMatchers [$ className ] = $ className ;
58+
59+ return $ this ;
60+ }
61+
3562 /**
3663 * A stable implementation of usort().
3764 *
@@ -46,14 +73,14 @@ public function getMatches($password, array $userInputs = [])
4673 * @param callable $value_compare_func
4774 * @return bool
4875 */
49- public static function usortStable (array &$ array , $ value_compare_func )
76+ public static function usortStable (array &$ array , callable $ value_compare_func )
5077 {
5178 $ index = 0 ;
5279 foreach ($ array as &$ item ) {
5380 $ item = array ($ index ++, $ item );
5481 }
5582 $ result = usort ($ array , function ($ a , $ b ) use ($ value_compare_func ) {
56- $ result = call_user_func ( $ value_compare_func, $ a [1 ], $ b [1 ]);
83+ $ result = $ value_compare_func( $ a [1 ], $ b [1 ]);
5784 return $ result == 0 ? $ a [0 ] - $ b [0 ] : $ result ;
5885 });
5986 foreach ($ array as &$ item ) {
@@ -78,16 +105,9 @@ public static function compareMatches(Match $a, Match $b)
78105 */
79106 protected function getMatchers ()
80107 {
81- // @todo change to dynamic
82- return [
83- Matchers \DateMatch::class,
84- Matchers \DictionaryMatch::class,
85- Matchers \ReverseDictionaryMatch::class,
86- Matchers \L33tMatch::class,
87- Matchers \RepeatMatch::class,
88- Matchers \SequenceMatch::class,
89- Matchers \SpatialMatch::class,
90- Matchers \YearMatch::class,
91- ];
108+ return array_merge (
109+ self ::DEFAULT_MATCHERS ,
110+ array_values ($ this ->additionalMatchers )
111+ );
92112 }
93113}
0 commit comments