Created
August 26, 2021 05:27
-
-
Save yosugi/b68a96eaab5f6351daa52bf95cca7fe8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace DataRenovationBundle\Util; | |
| use ArrayObject; | |
| /** | |
| * DataRenovationBundle\Utils\ArrayUtil | |
| * | |
| * 配列に関わるユーティリティ | |
| */ | |
| class ArrayUtil extends ArrayObject | |
| { | |
| public function __construct(array $array) | |
| { | |
| parent::__construct($array); | |
| } | |
| public static function init(array $array) | |
| { | |
| return new self($array); | |
| } | |
| public function toArray() | |
| { | |
| return (array) $this; | |
| } | |
| /** | |
| * 配列に指定されたキーがあればその値を、なければ default を返す | |
| * | |
| * @param mixed $key | |
| * @param bool $default | |
| * @param $predicate 何も指定しない場合 isset(), | |
| * true の場合 array_key_exists() | |
| * callable を指定した場合指定したもので判定する | |
| * @static | |
| * @return mixed | |
| * | |
| * 使用例 | |
| * | |
| * $array = ['a', 'b', null]; | |
| * | |
| * get($array, 0); // => 'a' | |
| * get($array, 3); // => null | |
| * get($array, 2, 'default'); // => 'default' | |
| * get($array, 2, 'default', true); // => null | |
| */ | |
| protected static function get($input, $key, $default = null, $predicate = null) | |
| { | |
| $restKey = []; | |
| if (is_array($key)) { | |
| $restKey = $key; | |
| $key = array_shift($restKey); | |
| } | |
| // isset で判定する場合 | |
| if (is_null($predicate)) { | |
| $predicate = function ($array, $key) { | |
| return isset($array[$key]); | |
| }; | |
| } | |
| // predicate で判定する場合 | |
| if (!is_callable($predicate)) { | |
| $predicate = function ($array, $key) { | |
| return array_key_exists($key, $array); | |
| }; | |
| } | |
| $value = (call_user_func($predicate, $input, $key)) ? $input[$key] : $default; | |
| if (empty($restKey)) return $value; | |
| if (!is_array($value)) return $default; | |
| return self::get($value, $restKey, $default, $predicate); | |
| } | |
| /** | |
| * 最初の null でない引数を返す | |
| * 全て null の場合は null を返す | |
| * | |
| * @static | |
| * @return mixed | |
| * | |
| * 例 | |
| * coalesce(null, 0, 1) // -> 0 | |
| * coalesce(null, null, 'a', 'b') // -> 'a' | |
| * coalesce(null, '', 'a', 'b') // -> '' | |
| */ | |
| public static function coalesce() | |
| { | |
| $args = func_get_args(); | |
| // 最初の null でないものを返す | |
| return self::find($args, function ($value) { | |
| return !is_null($value); | |
| }); | |
| } | |
| /** | |
| * 配列中で最初に $predicate を満たした値を返す | |
| * なかった場合、$notFound を返す | |
| * | |
| * @param callable $predicate | |
| * @param mixed $notFound | |
| * @static | |
| * @return mixed | |
| * | |
| * 例 | |
| * find([null, 0, 1]) // -> 1 | |
| * find(['', 1, 2]) // -> 1 | |
| * find([null, 0, '']) // -> null | |
| * find(['a', 'b', '2'], 'is_numeric') // -> '2' | |
| * find(['a', 'b', 'c'], 'is_numeric') // -> null | |
| * find(['a', 'b', 'c'], 'is_numeric', 'not found') // -> 'not found' | |
| */ | |
| protected static function find($input, callable $predicate = null, $notFound = null) | |
| { | |
| // デフォルトは真になるものを返す | |
| if (!is_callable($predicate)) { | |
| $predicate = function ($value) { | |
| return (boolean) $value; | |
| }; | |
| } | |
| // predicate を満たすものが見つかれば返す | |
| foreach ($input as $value) { | |
| $ret = call_user_func($predicate, $value); | |
| if ($ret) return $value; | |
| } | |
| // なければ $notFound を返す | |
| return $notFound; | |
| } | |
| /** | |
| * 配列の要素に function を適用する | |
| * | |
| * @param mixed $input | |
| * @param callable $function | |
| * @static | |
| * @return void | |
| */ | |
| protected static function map($input, callable $function) | |
| { | |
| $output = []; | |
| foreach ($input as $key => $value) { | |
| $output[$key] = call_user_func($function, $value, $key); | |
| } | |
| return $output; | |
| } | |
| /** | |
| * 配列の要素に function を適用する(キーも含む) | |
| * | |
| * @param mixed $input | |
| * @param callable $function | |
| * @static | |
| * @return void | |
| */ | |
| protected function mapWithKey($input, callable $function) | |
| { | |
| $output = []; | |
| foreach ($input as $key => $value) { | |
| $result = call_user_func($function, $key, $value); | |
| $output[key($result)] = current($result); | |
| } | |
| return $output; | |
| } | |
| /** | |
| * コールバック関数が true を返す要素のみ残す | |
| * | |
| * @param mixed $input | |
| * @param callable $predicate | |
| * @static | |
| * @return void | |
| */ | |
| protected static function filter($input, callable $predicate = null) | |
| { | |
| if ($predicate == null) { | |
| $predicate = function ($val) {return $val;}; | |
| } | |
| $output = []; | |
| foreach ($input as $key => $value) { | |
| if (!call_user_func($predicate, $value, $key)) continue; | |
| $output[$key] = $value; | |
| } | |
| return $output; | |
| } | |
| public function __call($name, $arguments) | |
| { | |
| if (!method_exists($this, $name)) { | |
| throw new \Exception('Call to undefined method ArrayUtil::' . $name); | |
| } | |
| array_unshift($arguments, $this); | |
| $result = call_user_func_array([$this, $name], $arguments); | |
| if (in_array($name, ['get', 'find'])) return $result; | |
| return ($result instanceof self) ? $result : new self($result); | |
| } | |
| public static function __callStatic($name, $arguments) | |
| { | |
| if (!method_exists(__CLASS__, $name)) { | |
| throw new BadMethodCallException('Call to undefined method ArrayUtil->' . $name); | |
| } | |
| return call_user_func_array([__CLASS__, $name], $arguments); | |
| } | |
| } | |
| /** | |
| * test code | |
| */ | |
| if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) { | |
| $array = [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| 'c' => 3, | |
| 'd' => [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| ], | |
| ]; | |
| assert(1 === ArrayUtil::get($array, 'a')); | |
| assert(1 === ArrayUtil::init($array)->get('a')); | |
| assert(null === ArrayUtil::get($array, 'nothing')); | |
| assert('default' === ArrayUtil::get($array, 'nothing', 'default')); | |
| assert(1 === ArrayUtil::get($array, ['a'])); | |
| $expect = [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| ]; | |
| assert($expect === ArrayUtil::get($array, 'd')); | |
| assert($expect === ArrayUtil::get($array, ['d'])); | |
| assert(null === ArrayUtil::get($array, ['a', 'b'])); | |
| assert(2 === ArrayUtil::get($array, ['d', 'b'])); | |
| assert('default' === ArrayUtil::get($array, ['d', 'c'], 'default')); | |
| assert(1 === ArrayUtil::find([null, 0, 1])); | |
| assert(1 === ArrayUtil::init([null, 0, 1])->find()); | |
| assert(1 === ArrayUtil::find(['', 1, 2])); | |
| assert(null === ArrayUtil::find([null, 0, ''])); | |
| assert('2' === ArrayUtil::find(['a', 'b', '2'], 'is_numeric')); | |
| assert(null === ArrayUtil::find(['a', 'b', 'c'], 'is_numeric')); | |
| assert('not found' === ArrayUtil::find(['a', 'b', 'c'], 'is_numeric', 'not found')); | |
| assert(0 === ArrayUtil::coalesce(null, 0, 1)); | |
| assert('a' === ArrayUtil::coalesce(null, null, 'a', 'b')); | |
| assert('' === ArrayUtil::coalesce(null, '', 'a', 'b')); | |
| $array = [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| 'c' => 3, | |
| ]; | |
| $expect = [ | |
| 'a' => 1, | |
| 'c' => 3, | |
| ]; | |
| $ret = ArrayUtil::filter($array, function ($value) { | |
| return $value % 2; | |
| }); | |
| assert($expect === $ret); | |
| $array = [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| 'c' => 3, | |
| ]; | |
| $expect = [ | |
| 'a' => 2, | |
| 'c' => 6, | |
| ]; | |
| $ret = ArrayUtil::init($array)->filter(function ($value) { | |
| return $value % 2; | |
| })->map(function ($value) { | |
| return $value * 2; | |
| })->toArray(); | |
| assert($expect === $ret); | |
| $array = [ | |
| 'a' => 1, | |
| 'b' => 2, | |
| 'c' => 3, | |
| ]; | |
| $expect = [ | |
| 'a' . 'a' => 1 + 1, | |
| 'b' . 'b' => 2 + 2, | |
| 'c' . 'c' => 3 + 3, | |
| ]; | |
| $ret = ArrayUtil::init($array)->mapWithKey(function ($key, $value) { | |
| return [$key . $key => $value + $value]; | |
| })->toArray(); | |
| assert($expect === $ret); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment