code: private function isParenthesisNeeded(Tokens $tokens, $argumentStartIndex, $argumentEndIndex)
      {
          static $allowedKinds = [
              T_DNUMBER, T_LNUMBER, T_VARIABLE, T_STRING, T_OBJECT_OPERATOR, T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_CAST,
              T_INT_CAST, T_INC, T_DEC, T_NS_SEPARATOR, T_WHITESPACE, T_DOUBLE_COLON, T_LINE, T_COMMENT, T_DOC_COMMENT,
              CT::T_NAMESPACE_OPERATOR,
          ];
  
          for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
              if ($tokens[$i]->isGivenKind($allowedKinds) || $tokens->isEmptyAt($i)) {
                  continue;
              }
  
              if (null !== $blockType = Tokens::detectBlockType($tokens[$i])) {
                  $i = $tokens->findBlockEnd($blockType['type'], $i);
  
                  continue;
              }
  
              if ($tokens[$i]->equals('$')) {
                  $i = $tokens->getNextMeaningfulToken($i);
                  if ($tokens[$i]->isGivenKind(CT::T_DYNAMIC_VAR_BRACE_OPEN)) {
                      $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE, $i);
  
                      continue;
                  }
              }
  
              if ($tokens[$i]->equals('+') && $tokens->getPrevMeaningfulToken($i) < $argumentStartIndex) {
                  continue;
              }
  
              return true;
          }
  
          return false;
      }
docs: @param Tokens $tokens
  @param int    $argumentStartIndex
  @param int    $argumentEndIndex
  
  @return bool