Replace the use of intval() and strval() as callbacks with a foreach and typecast or such

Created on 28 January 2023, over 1 year ago
Updated 23 January 2024, 5 months ago

Problem/Motivation

Follow-up to issue 📌 Replace intval(), strval(), .. *val() functions with their relevant type casting operators Postponed .

There are still three places where intval is used as a callback, which presumably would still be faster if replaced with a foreach and typecast or such:

core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php:      $ids = array_map('intval', $ids);
core/modules/language/src/LanguageNegotiator.php:    $enabled_methods = array_map('intval', $enabled_methods);
core/modules/views/src/Plugin/views/HandlerBase.php:      $value = array_map('intval', $value);

There are similarly any number of places where strval() is used as a callback:

[ayrton:drupal | Wed 04:53:21] $ grep -r "strval" * | grep -v "vendor" | grep -v "node_modules"
core/lib/Drupal/Core/Form/FormState.php:          if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php:    return array_map('strval', array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id)));
core/modules/views_ui/admin.inc:  if ($process_input && !$form_state->getTriggeringElement() && !empty($element['#is_button']) && isset($user_input[$element['#name']]) && isset($element['#values']) && in_array($user_input[$element['#name']], array_map('strval', $element['#values']), TRUE)) {
core/modules/toolbar/src/Ajax/SetSubtreesCommand.php:      'subtrees' => array_map('strval', $this->subtrees),
core/modules/migrate/src/Plugin/migrate/id_map/Sql.php:    return hash('sha256', serialize(array_map('strval', $source_id_values)));
core/modules/ckeditor5/src/HTMLRestrictions.php:            $value = array_map('strval', array_keys($value));
core/modules/views/src/Tests/ViewResultAssertionTrait.php:          $row[$expected_column] = is_array($field_value) ? array_map('strval', $field_value) : (string) $field_value;

Steps to reproduce

Grep for remaining usages of intval():
[ayrton:drupal | Wed 04:38:58] $ grep -r "intval" * | grep -v "vendor" | grep -v "node_modules"

Grep for remaining usages of strval():
[ayrton:drupal | Wed 04:53:21] $ grep -r "strval" * | grep -v "vendor" | grep -v "node_modules"

Proposed resolution

Replace the use of intval() and strval() as callbacks with a foreach and typecast or such

Remaining tasks

- Discuss the proposed resolution
- Replace the use of intval() and strval() as callbacks with a foreach and typecast or such
- Review

📌 Task
Status

Postponed: needs info

Version

11.0 🔥

Component
Base 

Last updated less than a minute ago

Created by

🇧🇷Brazil lucassc Rio de Janeiro

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Issue created by @lucassc
  • Assigned to PrabuEla
  • 🇮🇳India PrabuEla chennai

    The type cast changed but need bit deep testing for this.

  • Issue was unassigned.
  • Status changed to Needs review over 1 year ago
  • Status changed to Needs work over 1 year ago
  • 🇺🇸United States smustgrave

    Failures in #3

    Also new functions will need to be typehinted.

  • 🇬🇧United Kingdom catch
    +++ b/core/lib/Drupal/Core/Form/FormState.php
    @@ -1110,6 +1110,17 @@ class FormState implements FormStateInterface {
     
    +  /**
    +   * Type casting to sting.
    +   *
    +   * @return string $val.
    +   */
    +  public function toStringCasting($section = []) {
    +    foreach ($section as $val) {
    +      return (string) $val;
    +    }
    +  }
    +
       /**
    

    In the other issue where there's a 1-1 replacement for intval() or strval() to (int) or (string) that seems like a good micro-optmization. But it seems very unlikely to me that replacing a PHP function with a helper method is going to be an improvement at all, it's also a lot more code / less readable.

  • 🇮🇳India TanujJain-TJ

    Fixed failed commands on #3
    fixed phpcs errors
    Attached interdiff patch

  • First commit to issue fork.
  • Status changed to Needs review 6 months ago
  • 🇬🇷Greece dimitriskr

    Took another approach from what the patches had, tests are green

  • Status changed to Needs work 6 months ago
  • 🇺🇸United States smustgrave

    If a different approach was taken can the issue summary be updated to reflect new approach.

  • 🇷🇺Russia Chi

    The patch contains lots of irrelevant changes. Also I think the code with intval and strval callbacks is much more readable.

  • Status changed to Needs review 6 months ago
  • 🇬🇷Greece dimitriskr

    I mean I took a different approach than the patches, I believe the code in MR reflects the proposed resolution in IS

  • 🇺🇸United States smustgrave

    The patch contains lots of irrelevant changes.

    @chi could you flag those in the MR.

  • 🇷🇺Russia Chi

    @smustgrave, I think the parent issue is outdated. There was a big difference indeed in PHP 5 but in PHP 8 it works equally well.

    Here is the script I used for testing.

    const LIMIT = 10_000_000;
    
    // -- (string)
    $start = \microtime(true);
    
    for($i = 0; $i < \LIMIT; $i++) {
      $a = (string) $i;
    }
    
    $end = \microtime(true);
    echo ' (string): ', \number_format(1_000 * ($end - $start), 2), ' ms', \PHP_EOL;
    
    // -- strval
    $start = \microtime(true);
    
    for($i = 0; $i < \LIMIT; $i++) {
      $b = \strval($i);
    }
    
    $end = \microtime(true);
    echo '   strval: ', \number_format(1_000 * ($end - $start), 2), ' ms', \PHP_EOL;
    
    // -- callback
    $to_string = static fn ($value): string => (string) $value;
    $start = \microtime(true);
    
    for($i = 0; $i < \LIMIT; $i++) {
      $c = $to_string($i);
    }
    
    $end = \microtime(true);
    echo ' Callback: ', \number_format(1_000 * ($end - $start), 2), ' ms', \PHP_EOL;
    

    Result (PHP 8.2):

     (string): 190.62 ms
       strval: 192.26 ms
     Callback: 340.39 ms
    

    The approach with custom caster works a way slower than strval. But even if it would be faster, notice the absolute values. 179 milliseconds for 10 million iterations. It's not a micro-optimization nor even a nano-optimization. It's a pico-optimization. )

  • 🇬🇧United Kingdom longwave UK

    Unless this was in a super tight critical loop, to me we should prefer readability over micro-optimisations, and this should be closed won't fix as calling a custom method in order to cast instead of using array_map('intval', ...) is much harder to understand.

  • 🇬🇷Greece dimitriskr

    The script in #16 is good for the parent issue. Here it's about arrays and typecasting their values so it might have some differencein performance?

    Also I ran the script too and got different results

     (string): 697.98 ms
       strval: 715.63 ms
     Callback: 2,925.63 ms
    
  • 🇺🇸United States smustgrave

    So should this be postponed till the parent issue can be updated to determine if this issue should move forward?

  • Status changed to Postponed: needs info 5 months ago
  • 🇺🇸United States smustgrave

    With regards to #19

Production build 0.69.0 2024