New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.7] Inline Arr::pluck() in data_get() #25938

Merged
merged 1 commit into from Oct 5, 2018

Conversation

Projects
None yet
2 participants
@vlakoff
Contributor

vlakoff commented Oct 4, 2018

Follow-up to #25892. Cherry-picked from it a small code inlining.

  • avoids "cross-calling" between these two methods
  • 10~20% performance boost

I think this way the code is clearer (shows the recursivity) and safer (more encapsulated, avoids interconnection).

The performance benefit can be interesting too, as the function appears to be O(n) depending on the size of input data. So with thousands of users, the function can become slow; with this change the function is still slow, but with a small improvement worth picking.

Bench on PHP 7.2.10:

0.71760010719299
0.63960003852844

89.130426837635

$array = array_fill(0, 500, ['name' => 'taylor']);
$nb = 1000;

$t1 = microtime(true);
for ($ii = $nb; $ii--; ) {
    data_get($array, '*.name');
}
$t2 = microtime(true);
for ($ii = $nb; $ii--; ) {
    data_get_2($array, '*.name');
}
$t3 = microtime(true);

echo $t2 - $t1;
echo '<br>';
echo $t3 - $t2;
echo '<br><br>';
echo $t2 - $t1 == 0 ? 'N/A' : ($t3 - $t2) * 100 / ($t2 - $t1);
function data_get_2($target, $key, $default = null)
{
    if (is_null($key)) {
        return $target;
    }

    $key = is_array($key) ? $key : explode('.', $key);

    while (! is_null($segment = array_shift($key))) {
        if ($segment === '*') {
            if ($target instanceof Collection) {
                $target = $target->all();
            } elseif (! is_array($target)) {
                return value($default);
            }

            $result = [];

            foreach ($target as $item) {
                $result[] = data_get_2($item, $key);
            }

            return in_array('*', $key) ? Arr::collapse($result) : $result;
        }

        if (Arr::accessible($target) && Arr::exists($target, $segment)) {
            $target = $target[$segment];
        } elseif (is_object($target) && isset($target->{$segment})) {
            $target = $target->{$segment};
        } else {
            return value($default);
        }
    }

    return $target;
}
Inline Arr::pluck() in data_get()
- avoids "cross-calling" between these two methods
- 10~20% performance boost

@taylorotwell taylorotwell merged commit 2ab2fc6 into laravel:5.7 Oct 5, 2018

2 checks passed

continuous-integration/styleci/pr The analysis has passed
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@vlakoff vlakoff deleted the vlakoff:data_get_2 branch Oct 5, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment