Skip to content

Use better error message for non-numeric strings in implicit contexts #20632

Open

Description

@IMSoP

Description

When a "non-numeric" string is coerced to an integer or float, PHP raises an error rather than proceeding with the implicit cast. This is a good thing.

However, the error message implies that any string would be invalid, rather than that the content of the string is the problem.

Additionally, a common cause in my experience is that the string is empty, for instance, missing from some input data. It would be helpful for debugging to highlight when this is the case.

Proposal

When coercion to a numeric, float, or int context fails:

  • If the string being coerced is empty, use "empty string" as a pseudo-type in the error message
  • Otherwise, use "non-numeric string" as a pseudo-type in the error message

Current Behaviour

Mathematical operators:

echo 1 + "1";
// 2
echo 1 + "hello";
// TypeError: Unsupported operand types: int + string
echo 1 + "";
// TypeError: Unsupported operand types: int + string

Function calls in coercive-call mode:

declare(strict_types=0);

function foo(int $a) { echo $a; }

foo("1");
// 1
foo("a");
// TypeError: foo(): Argument #1 ($a) must be of type int, string given
foo("");
// TypeError: foo(): Argument #1 ($a) must be of type int, string given

Proposed behaviour

Mathematical operators:

echo 1 + "1";
// 2
echo 1 + "hello";
// TypeError: Unsupported operand types: int + non-numeric string
echo 1 + "";
// TypeError: Unsupported operand types: int + empty string

Function calls in coercive-call mode:

declare(strict_types=0);

function foo(int $a) { echo $a; }

foo("1");
// 1
foo("a");
// TypeError: foo(): Argument #1 ($a) must be of type int, non-numeric string given
foo("");
// TypeError: foo(): Argument #1 ($a) must be of type int, empty string given

Activity

  1. iluuu1994 commented on Dec 3, 2025

    @iluuu1994
    Member

    Also worth noting that we already have some error messages that include truncated user strings: https://3v4l.org/JS32G#v8.5.0 Maybe that would make things even clearer.

  2. IMSoP commented on Dec 3, 2025

    @IMSoP
    ContributorAuthor

    Also worth noting that we already have some error messages that include truncated user strings: https://3v4l.org/JS32G#v8.5.0 Maybe that would make things even clearer.

    Ah, nice; I was worried about non-printables, but that seems to have been handled: https://3v4l.org/61dhi#v8.5.0

    I think including the "non-numeric" (or similar) is still important, to avoid people assuming that any string would be a problem, so maybe:

    TypeError: Unsupported operand types: int + non-numeric string ('hello')
    TypeError: Unsupported operand types: int + non-numeric string ('')

    TypeError: foo(): Argument #1 ($a) must be of type int, non-numeric string ('hello') given
    TypeError: foo(): Argument #1 ($a) must be of type int, non-numeric string ('') given

    That would be really handy for debugging something like $price = '£20'; ... $total = $price * $quantity;

  3. mvorisek commented on Dec 3, 2025

    @mvorisek
    Contributor

    I support non-numeric-string (and possibly empty-string) as the "truncated user string" might be not enough and also it is available in backtrace.

  4. rizwan3d commented on Dec 4, 2025

    @rizwan3d

    Hi @iluuu1994,
    could you please review this change when you have a moment? Thanks! 🙏

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions