Skip to content

Loose in_array(string, array, false) on array with mix of string and objects will __toString() those objects ONLY when the first array entry is an object #18625

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

Closed
phoenixz opened this issue May 23, 2025 · 2 comments

Comments

@phoenixz
Copy link

Description

The following code:

<?php
<?php
class Test {
    public function __toString(): string
    {
        die('fail!' . PHP_EOL);
    }
}

$a = [
    'string' => 'test', //  // <=== First position is a string
    'object' => new Test()
];

print_r(in_array('test', $a)); This displays "1", correctly.
echo PHP_EOL;
print_r($a); // This displays the array, correctly, all works as expected

$a = [
    'object' => new Test(), // <=== object is now on first position
    'string' => 'test',
];

print_r(in_array('test', $a)); // Script dies here with "fail!" because in_array() executed Test::__toString()
print_r($a);

Resulted in this output:

1
Array
(
    [string] => test
    [object] => Test Object
        (
        )

)
fail!

But I expected this output instead:

1
Array
(
    [object] => Test Object
        (
        )

    [string] => test
)
1
Array
(
    [object] => Test Object
        (
        )

    [string] => test
)

PHP Version

PHP 8.3.6 (cli) (built: Mar 19 2025 10:08:38) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.6, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.6, Copyright (c), by Zend Technologies

Operating System

Ubuntu 24.04.2 LTS

@pospjan
Copy link

pospjan commented May 23, 2025

@phoenixz It's not about the object being (or not being) on the first place, but that the string you are looking for was already found (in_array stops checking other items as it can already return true).

If you modify your first array like this:

$a = [
    'string' => 'test',
    'object' => new Test(),
    'string2' => 'test2', 
];

print_r(in_array('test2', $a)); 

It fails.

@iluuu1994
Copy link
Member

Indeed. As explained, nothing surprising is going on here. Loose in_array() comparison does string coercion, and it does so element by element. If your __toString() exists the script, there's nothing we can do about that.

@iluuu1994 iluuu1994 closed this as not planned Won't fix, can't repro, duplicate, stale May 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants