diff --git a/src/error/PhutilErrorHandler.php b/src/error/PhutilErrorHandler.php --- a/src/error/PhutilErrorHandler.php +++ b/src/error/PhutilErrorHandler.php @@ -181,7 +181,6 @@ * @task internal */ public static function handleError($num, $str, $file, $line, $ctx = null) { - foreach (self::$traps as $trap) { $trap->addError($num, $str, $file, $line); } @@ -378,7 +377,7 @@ * @task internal */ public static function dispatchErrorMessage($event, $value, $metadata) { - $timestamp = strftime('%Y-%m-%d %H:%M:%S'); + $timestamp = date('Y-m-d H:i:s'); switch ($event) { case self::ERROR: diff --git a/src/filesystem/linesofalarge/LinesOfALarge.php b/src/filesystem/linesofalarge/LinesOfALarge.php --- a/src/filesystem/linesofalarge/LinesOfALarge.php +++ b/src/filesystem/linesofalarge/LinesOfALarge.php @@ -212,7 +212,7 @@ if (strlen($this->buf)) { $this->num++; $this->line = $this->buf; - $this->buf = null; + $this->buf = ''; } else { $this->valid = false; } diff --git a/src/future/exec/ExecFuture.php b/src/future/exec/ExecFuture.php --- a/src/future/exec/ExecFuture.php +++ b/src/future/exec/ExecFuture.php @@ -199,7 +199,7 @@ (string)substr($this->stderr, $this->stderrPos), ); - $this->stderrPos = strlen($this->stderr); + $this->stderrPos = $this->getStderrBufferLength(); return $result; } @@ -210,7 +210,8 @@ } $result = (string)substr($this->stdout, $this->stdoutPos); - $this->stdoutPos = strlen($this->stdout); + $this->stdoutPos = $this->getStdoutBufferLength(); + return $result; } @@ -475,7 +476,7 @@ * @task internal */ public function isReadBufferEmpty() { - return !strlen($this->stdout); + return !$this->getStdoutBufferLength(); } @@ -757,14 +758,17 @@ $max_stdout_read_bytes = PHP_INT_MAX; $max_stderr_read_bytes = PHP_INT_MAX; if ($read_buffer_size !== null) { - $max_stdout_read_bytes = $read_buffer_size - strlen($this->stdout); - $max_stderr_read_bytes = $read_buffer_size - strlen($this->stderr); + $stdout_len = $this->getStdoutBufferLength(); + $stderr_len = $this->getStderrBufferLength(); + + $max_stdout_read_bytes = $read_buffer_size - $stdout_len; + $max_stderr_read_bytes = $read_buffer_size - $stderr_len; } if ($max_stdout_read_bytes > 0) { $this->stdout .= $this->readAndDiscard( $stdout, - $this->getStdoutSizeLimit() - strlen($this->stdout), + $this->getStdoutSizeLimit() - $this->getStdoutBufferLength(), 'stdout', $max_stdout_read_bytes); } @@ -772,7 +776,7 @@ if ($max_stderr_read_bytes > 0) { $this->stderr .= $this->readAndDiscard( $stderr, - $this->getStderrSizeLimit() - strlen($this->stderr), + $this->getStderrSizeLimit() - $this->getStderrBufferLength(), 'stderr', $max_stderr_read_bytes); } @@ -1013,5 +1017,20 @@ ); } + private function getStdoutBufferLength() { + if ($this->stdout === null) { + return 0; + } + + return strlen($this->stdout); + } + + private function getStderrBufferLength() { + if ($this->stderr === null) { + return 0; + } + + return strlen($this->stderr); + } } diff --git a/src/future/http/BaseHTTPFuture.php b/src/future/http/BaseHTTPFuture.php --- a/src/future/http/BaseHTTPFuture.php +++ b/src/future/http/BaseHTTPFuture.php @@ -206,12 +206,14 @@ * @task config */ public function getHeaders($filter = null) { - $filter = strtolower($filter); + if ($filter !== null) { + $filter = phutil_utf8_strtolower($filter); + } $result = array(); foreach ($this->headers as $header) { list($name, $value) = $header; - if (!$filter || ($filter == strtolower($name))) { + if (($filter === null) || ($filter === phutil_utf8_strtolower($name))) { $result[] = $header; } } diff --git a/src/future/http/HTTPSFuture.php b/src/future/http/HTTPSFuture.php --- a/src/future/http/HTTPSFuture.php +++ b/src/future/http/HTTPSFuture.php @@ -269,7 +269,7 @@ curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, $allowed_protocols); } - if (strlen($this->rawBody)) { + if ($this->rawBody !== null) { if ($this->getData()) { throw new Exception( pht( diff --git a/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php @@ -17,6 +17,14 @@ continue; } + // Don't warn about PHP comment directives. In particular, we need + // to use "#[\ReturnTypeWillChange]" to implement "Iterator" in a way + // that is compatible with PHP 8.1 and older versions of PHP prior + // to the introduction of return types. See T13588. + if (preg_match('/^#\\[\\\\/', $value)) { + continue; + } + $this->raiseLintAtOffset( $comment->getOffset(), pht( diff --git a/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test b/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/comment-style/hash-directives.lint-test @@ -0,0 +1,23 @@ +throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function key() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function next() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function rewind() { $this->throwOnAttemptedIteration(); } + #[\ReturnTypeWillChange] public function valid() { $this->throwOnAttemptedIteration(); } diff --git a/src/parser/PhutilURI.php b/src/parser/PhutilURI.php --- a/src/parser/PhutilURI.php +++ b/src/parser/PhutilURI.php @@ -166,7 +166,7 @@ if ($this->isGitURI()) { $protocol = null; } else { - if (strlen($auth)) { + if ($auth !== null) { $protocol = nonempty($this->protocol, 'http'); } } diff --git a/src/parser/argument/PhutilArgumentParser.php b/src/parser/argument/PhutilArgumentParser.php --- a/src/parser/argument/PhutilArgumentParser.php +++ b/src/parser/argument/PhutilArgumentParser.php @@ -769,7 +769,12 @@ pht('There is no **%s** workflow.', $workflow_name)); } else { $out[] = $this->indent($indent, $workflow->getExamples()); - $out[] = $this->indent($indent, $workflow->getSynopsis()); + + $synopsis = $workflow->getSynopsis(); + if ($synopsis !== null) { + $out[] = $this->indent($indent, $workflow->getSynopsis()); + } + if ($show_details) { $full_help = $workflow->getHelp(); if ($full_help) { diff --git a/src/symbols/PhutilClassMapQuery.php b/src/symbols/PhutilClassMapQuery.php --- a/src/symbols/PhutilClassMapQuery.php +++ b/src/symbols/PhutilClassMapQuery.php @@ -226,8 +226,8 @@ $unique = $this->uniqueMethod; $sort = $this->sortMethod; - if (strlen($expand)) { - if (!strlen($unique)) { + if ($expand !== null) { + if ($unique === null) { throw new Exception( pht( 'Trying to execute a class map query for descendants of class '. @@ -245,7 +245,7 @@ ->loadObjects(); // Apply the "expand" mechanism, if it is configured. - if (strlen($expand)) { + if ($expand !== null) { $list = array(); foreach ($objects as $object) { foreach (call_user_func(array($object, $expand)) as $instance) { @@ -257,7 +257,7 @@ } // Apply the "unique" mechanism, if it is configured. - if (strlen($unique)) { + if ($unique !== null) { $map = array(); foreach ($list as $object) { $key = call_user_func(array($object, $unique)); @@ -287,12 +287,12 @@ } // Apply the "filter" mechanism, if it is configured. - if (strlen($filter)) { + if ($filter !== null) { $map = mfilter($map, $filter); } // Apply the "sort" mechanism, if it is configured. - if (strlen($sort)) { + if ($sort !== null) { if ($map) { // The "sort" method may return scalars (which we want to sort with // "msort()"), or may return PhutilSortVector objects (which we want diff --git a/src/workflow/ArcanistWorkflow.php b/src/workflow/ArcanistWorkflow.php --- a/src/workflow/ArcanistWorkflow.php +++ b/src/workflow/ArcanistWorkflow.php @@ -143,7 +143,7 @@ if ($information) { $synopsis = $information->getSynopsis(); - if (strlen($synopsis)) { + if ($synopsis !== null) { $phutil_workflow->setSynopsis($synopsis); }