"""Checking whether an array is empty with a strict comparison against the empty array is a common pattern in PHP. A GitHub search for "=== []" language:PHP reveals 44k hits. From the set of !$a, count($a) === 0, empty($a) and $a === [] it however is also the slowest option."""

https://github.com/php/php-src/pull/18571

This is a great example of how you should write whatever you find most readable and maintainable, and let us worry about efficiency. Wtih this PR, the "slow" approach becomes a "fast" one.

zend_vm: Add OPcode specialization for `=== []` by TimWolla · Pull Request #18571 · php/php-src

Checking whether an array is empty with a strict comparison against the empty array is a common pattern in PHP. A GitHub search for "=== []" language:PHP reveals 44k hits. From the set of...

GitHub
@pollita
One that bothers me is array_map/array_walk functions, from what I've read and tested (some time ago), it's always slower than foreach because of the call overhead, and not suited for huge arrays.
This is sad because on a codestyle perspective I find it cleaner to chain array_map, array_filter, array_unique and friends.
Inline array_map(fn, $arr) and use foreach-loop instead by staabm · Pull Request #1502 · Roave/BetterReflection

Based on a perf review togehter with nielsdos (php-src core develoepr) we identified array_map, when used with a callback function to be a hotspot in PHPStan analysis, see https://phpc.social/@mark...

GitHub
@ocramius @come @pollita There were some improvements, but a plain `foreach()` loop is still going to beat `array_map()`. And trying to optimize `array_map()` into a loop is likely going to be hard, because of the semantics around scoping and type checking of the closure (both parameter and return types).
@timwolla @come @pollita yeah, but maybe, one day, we may get TCO from somewhere 🥹
@ocramius @timwolla @come @pollita maybe https://github.com/php/php-src/pull/18204 could help to reduce the overhead if the callback consuming functions
[PoC] Implement some internal functions in plain PHP by arnaud-lb · Pull Request #18204 · php/php-src

This is a very quick PoC of @staabm's idea in #17536 (comment). This PR implements array_find() and related functions in plain PHP, and removes the C implementation. Idea As seen in #17536, int...

GitHub
@pollita This is great! I’ve been using `=== []` because logic dictates it should be faster than a function call (i.e., `count($a) === 0`). I had no idea it was the slower option.
@ramsey Count is usually not a function call, it's a dedicated opcode
@nielsdos @ramsey Within namespaces it's important to point out that this optimization only happens with fully-qualifying the call to `count()`. Either as `\count()` or via `use function count;`. Otherwise a `count()` function could exist in the namespace.
@timwolla True. Which makes me wonder whether it makes sense to emit a JMP_FRAMELESS opcode, not to call these functions framelessly, but to try to use the dedicated op anyway. Maybe I should try this
@nielsdos @timwolla Isn't the problem the fallback to global namespace the problem? As I'm not really sure how you will be able to get from the opcode that does this to the call one being frameless
@Girgias @timwolla The idea is to do something like this (in pseudocode):
01 JMP_FRAMELESS 04 string("foo\\strlen")
... etc
02 V0 = DO_FCALL_BY_NAME
03 JMP 05
04 V0 = COUNT ...
05 Do something with V0
@ramsey @pollita wow, it's never occurred to me to do that, always used count == 0

@ramsey @pollita sounds like $a++ is slower than ++$a because assembly used to have a different number of operations for both (or something like this)

Or COUNT(1) is faster than COUNT(*) because that last one first expands into the list of fields (disregarding the query optimizer)

Or beware the 6 fingers, that’s how you tell it’s ai generated

A lot of the early knowledge we took pains to gather, turns out to be noise

@GuillaumeRossolini @ramsey *Technically* $a++ is still slower than ++$a, because the former has to create a tempvar to save rhe value prior to the increment, what the latter can iincrement and just forward fhe new value.

Technically, because *every* compiler for *every* language quietly transforms $a++ into ++$a when it can see the result is not used.

@pollita @ramsey this only further supports your original argument 😂

@pollita @GuillaumeRossolini @ramsey Except C++, I guess 😜

https://godbolt.org/z/o48rcvGzz

#include <iostream>

struct Foo {
void operator++() {
std::cout << "pre\n";
}

void operator++(int) {
std::cout << "post\n";
}
};

int
main(void) {
Foo f;

f++;
}

Compiler Explorer - C++ (x86-64 gcc 15.1)

struct Foo { void operator++() { std::cout << "pre\n"; } void operator++(int) { std::cout << "post\n"; } }; int main(void) { Foo f; f++; }

@timwolla @GuillaumeRossolini @ramsey That's a contrived (and flawed) counter-example. The compiler can see that the operators are overridden, so it knows not to elide the side-effects. Same as it would if the result were consumed:

# int a; ++a;
add DWORD PTR [rbp-4], 1
# int b; b++;
add DWORD PTR [rbp-8], 1

@pollita @GuillaumeRossolini @ramsey Of course it is (as indicated by the Emoji) 😀
@timwolla @GuillaumeRossolini @ramsey Sorry, that seems obvious in hindsight. :p
@pollita I use a code quality plugin in my IDE that warms about slow constructs that I'm sure were optimised like in PHP 7.0.
@pollita I thought exactly this when I read https://mastodon.green/@IvoBathke/114500409956860739 😅
Ivo Bathke (@IvoBathke@mastodon.green)

Do not use try/catch with exceptions in loops. Throwing exceptions is expensive and performance will degrade significantly. Just got bitten by this 😅. This post explains it quite good: https://php.watch/articles/php-exception-performance #php

Mastodon.green
@pollita I thought most of these micro optimizations were absorbed by opcache, anyway
@GuillaumeRossolini They are, in that opcache contains an optimizer.