Fixes to GH-14078:
* Rename ZipArchive::openBuffer() to ::openString().
* For consistency with ::open(), return int|bool, don't throw an
exception on error. Provide error information via existing properties
and accessors.
* Fix memory leak when ::openString() is called but ::close() is not
called. Add test.
* Fix memory leak when a call to ::open() is followed by a call to
::openString(). Add test.
* Let libzip own the source, don't call zip_source_keep().
* Share buffer handling with ZipArchive::addFromString().
Elsewhere:
* If there is an error from zip_close() during a call to
ZipArchive::open(), emit a warning but proceed to open the archive,
don't return early. Add test.
* When buffers are saved by ZipArchive::addFromString(), release them
in ZipArchive::close() and ::open(), don't accumulate buffers until
the free_obj handler is called.
* Factor out buffer handling and reuse it in ZipArchive::openString()
Closes GH-21205.
Closes GH-14078.
Co-authored-by: Soner Sayakci <s.sayakci@shopware.com>
Co-authored-by: Ghaith Olabi <24876890+Gaitholabi@users.noreply.github.com>
internal refactorings:
- pcntl_signal_get_handler() max signals handling simplification,
reusing the num_signals global.
- pcntl_alarm() accepts a zend_long (signed) but passes it to alarm(),
which takes an unsigned int. Negative values silently wrap to large
unsigned values, scheduling an alarm far in the future instead of
raising an error. Also reject large values above unsigned long
max value.
close GH-21282
When a PCRE execution error occurs (e.g. malformed UTF-8 with /u
modifier), preg_grep() was returning a partial result array containing
only the entries processed before the error. All other preg_* functions
return false on execution errors.
After the match loop, check PCRE_G(error_code) and if an error
occurred, destroy the partial array and return false instead.
Fixes GH-11936
The remote resources don't work because remote streams don't have a stat
method.
Since the check is only here for a best-effort check to return
"directory" instead of "empty", we can try the stat and still execute
the magic_stream() code even if it failed. Unfortunately we can't
distinguish between a failed stat and an unimplemented stat. If we
could, then this code could be even more robust.
This removes the artificial limitation that is not necessary. The fact
that some streams can have some data buffered is not a problem because
the similar situation is already present for OpenSSL streams where
OpenSSL can internally buffer data for the unprocessed part of the
record.
Closes GH-20540
This adds so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt
stream socket context options that are used to set their upper case
C macro variants by setsockopt function.
The test requires sockets extension and just tests that the values are
being set. This is because a real test would be slow and difficult to
show that those options really work due to how they work internally.
Closes GH-20381
Set TCP_USER_TIMEOUT to cap (ms) how long TCP will wait for ACKs on in-flight data
before aborting the connection; prevents stuck/half-open sessions and
enables faster failover vs default retransmission timeouts.
Co-authored-by: David Carlier <devnexen@gmail.com>
close GH-20708
* Implement clamp function
Co-authored-by: thinkverse <hallberg.kim@gmail.com>
* - Use a common function for normal and frameless implementations
- Add tests for null and not-comparable cases
- Fix object support for frameless clamp function
- Improve NAN handling
* Create tests triggering both frameless and dynamic variants
* Add changelog
* [Review] rephrase error messages to use "must not"
* Enable assert()
---------
Co-authored-by: thinkverse <hallberg.kim@gmail.com>
While it is possible to return a custom SplFileInfo object in the
iterator used by buildFromIterator(), the data is not actually used from
that object, instead the data from the underlying internal structure is
used. This makes it impossible to override some metadata such as the
path name and modification time.
The main motivation comes from two reasons:
- Consistency. We expect our custom methods to be called when having a
custom object.
- Support reproducibility. This is the original use case as requested in
[1].
Add support for this by calling the getMTime() and getPathname() methods
if they're overriden by a user class.
[1] https://github.com/theseer/Autoload/issues/114.
Three optimizations:
- If the entire string is returned, we don't need to duplicate it.
- Use packed filling logic.
- Use fast construction of strings. This is useful when splitting
strings on length=1. In that case I get a 6x speedup in the code
below.
Bench:
```php
$x = str_repeat('A', 100);
for ($i = 0; $i < 1000000; $i++)
str_split($x, 10);
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 160.1 ms ± 6.4 ms [User: 157.3 ms, System: 1.8 ms]
Range (min … max): 155.6 ms … 184.7 ms 18 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 202.6 ms ± 4.0 ms [User: 199.1 ms, System: 1.9 ms]
Range (min … max): 197.4 ms … 209.2 ms 14 runs
Summary
./sapi/cli/php x.php ran
1.27 ± 0.06 times faster than ./sapi/cli/php_old x.php
```
The performance gain increases with smaller lengths.
For this benchmark:
```php
<?php
for ($i = 0; $i < 10000000; $i++) {
intval('+0b11111111111100000000', 2);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 527.3 ms ± 8.1 ms [User: 523.5 ms, System: 2.4 ms]
Range (min … max): 515.4 ms … 545.1 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 629.3 ms ± 6.0 ms [User: 625.9 ms, System: 1.8 ms]
Range (min … max): 622.8 ms … 643.2 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.19 ± 0.02 times faster than ./sapi/cli/php_old x.php
```
Closes GH-20357.
Packed arrays are likely common in this case, as with array_shift which
already has a similar optimization.
For the following benchmark:
```php
<?php
for ($i = 0; $i < 10000000; $i++) {
$a = [0, 1, 2, 3, 4, 5];
array_unshift($a, -3, -2, -1);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 753.8 ms ± 23.8 ms [User: 749.8 ms, System: 2.1 ms]
Range (min … max): 734.3 ms … 818.6 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 972.5 ms ± 5.0 ms [User: 968.8 ms, System: 1.4 ms]
Range (min … max): 967.8 ms … 984.3 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.29 ± 0.04 times faster than ./sapi/cli/php_old x.php
```
We never need to use refcounted copies for arguments because the copy to
the call frame already increments the refcount.
For the following benchmark:
```php
$a = range(0, 10);
for ($i = 0; $i < 1000000; $i++)
array_walk($a, fn ($val, $idx, $arg) => $val + $arg, 2);
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 593.0 ms ± 5.4 ms [User: 589.8 ms, System: 1.7 ms]
Range (min … max): 583.3 ms … 600.9 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 637.8 ms ± 4.6 ms [User: 633.9 ms, System: 2.2 ms]
Range (min … max): 633.4 ms … 649.2 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.08 ± 0.01 times faster than ./sapi/cli/php_old x.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 362.3 ms ± 2.0 ms [User: 359.9 ms, System: 1.9 ms]
Range (min … max): 359.6 ms … 367.1 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 385.5 ms ± 1.8 ms [User: 383.2 ms, System: 1.9 ms]
Range (min … max): 381.5 ms … 387.2 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.06 ± 0.01 times faster than ./sapi/cli/php_old x.php
```
Move the refcount update outside of the loop.
For the following benchmark:
```php
$r = range(0, 1000);
$v = new stdClass();
for ($i = 0; $i < 100000; $i++) {
array_fill_keys($r, $v);
}
```
On an i7-4790:
```
Benchmark 1: ./sapi/cli/php_old ../x.php
Time (mean ± σ): 507.5 ms ± 4.8 ms [User: 505.1 ms, System: 1.2 ms]
Range (min … max): 501.2 ms … 518.4 ms 10 runs
Benchmark 2: ./sapi/cli/php ../x.php
Time (mean ± σ): 479.8 ms ± 3.1 ms [User: 476.8 ms, System: 1.8 ms]
Range (min … max): 475.0 ms … 486.7 ms 10 runs
Summary
./sapi/cli/php ../x.php ran
1.06 ± 0.01 times faster than ./sapi/cli/php_old ../x.php
```
On an i7-1185G7:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 343.9 ms ± 3.1 ms [User: 341.1 ms, System: 2.3 ms]
Range (min … max): 337.9 ms … 347.8 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 357.8 ms ± 2.3 ms [User: 355.7 ms, System: 1.6 ms]
Range (min … max): 355.0 ms … 362.6 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.04 ± 0.01 times faster than ./sapi/cli/php_old x.php
```
This avoids duplicating the intermediate strings, by transferring
ownership.
It's hard to measure the improvement in a reliable way, as we have to
operate on the same node. The following benchmark shows a nice
improvement (although not perfect as a benchmark):
```php
<?php
$dom = new DOMDocument;
$dom->loadXML('<root>testabcdef</root>');
$text = $dom->documentElement->firstChild;
for ($i = 0; $i < 1000000; $i++) {
$text2 = clone $text;
$text2->splitText(5);
}
```
Only tested on my desktop i7-4790:
```
Benchmark 1: ./sapi/cli/php x.php
Time (mean ± σ): 284.1 ms ± 2.8 ms [User: 280.0 ms, System: 3.0 ms]
Range (min … max): 281.4 ms … 291.3 ms 10 runs
Benchmark 2: ./sapi/cli/php_old x.php
Time (mean ± σ): 314.0 ms ± 7.8 ms [User: 309.2 ms, System: 2.9 ms]
Range (min … max): 306.5 ms … 328.0 ms 10 runs
Summary
./sapi/cli/php x.php ran
1.11 ± 0.03 times faster than ./sapi/cli/php_old x.php
```
This is to allow disabling of SO_REUSEADDR that is enabled by default.
To achieve better compatibility on Windows SO_EXCLUSIVEADDRUSE is set
if so_reuseaddr is false.
Closes GH-19967
* zend_compile: Add `is_func_accessible()` helper
* zend_compile: Use `zend_set_class_name_op1()` in `zend_compile_new()`
* zend_compile: Optimize arguments for ZEND_NEW
Apply the optimization for static method calls to `new` calls, since `new` is
effectively a static method for all intents and purposes.
For:
<?php
final class MyClass
{
private function __construct(
private \Random\Engine $foo,
private int $bar = 0,
) {}
public static function new(int $bar): self
{
$engine = new \Random\Engine\Xoshiro256StarStar(seed: 123);
return new self(foo: $engine, bar: $bar);
}
}
for ($i = 0; $i < 3_000_000; $i++) {
MyClass::new($i);
}
This is ~1.13 faster for a gcc 13.3 release build on a Intel(R) Core(TM)
i7-1365U.
Benchmark 1: /tmp/bench/php.old /tmp/bench/test6.php
Time (mean ± σ): 409.5 ms ± 1.9 ms [User: 406.6 ms, System: 2.2 ms]
Range (min … max): 407.4 ms … 414.0 ms 10 runs
Benchmark 2: /tmp/bench/php.new /tmp/bench/test6.php
Time (mean ± σ): 360.9 ms ± 1.7 ms [User: 358.5 ms, System: 2.2 ms]
Range (min … max): 359.2 ms … 365.0 ms 10 runs
Summary
/tmp/bench/php.new /tmp/bench/test6.php ran
1.13 ± 0.01 times faster than /tmp/bench/php.old /tmp/bench/test6.php
Previously this failed as the read_dimension which is invoked by
ref-assign does not contain the logic to add the key, so it was required
to first write the value using a normal assignment and then thereafter
use the reference assignment.
This solves it by adding the necessary logic to assign references
directly.
Instead of using a boolean flag to check for each element whether or not it is
the first, we just unconditionally append a comma after each element and then
remove the last comma at the end.
For:
<?php
$len = 0;
for ($i = 0; $i < 3_000_000; $i++) {
$len += strlen(json_encode(array_fill(0, 20, [])));
}
var_dump($len);
This is ~1.06 faster for a gcc 13.3 release build on a Intel(R) Core(TM)
i7-1365U.
Benchmark 1: /tmp/bench/before /tmp/bench/test6.php
Time (mean ± σ): 819.6 ms ± 2.8 ms [User: 816.4 ms, System: 2.4 ms]
Range (min … max): 816.9 ms … 825.0 ms 10 runs
Benchmark 2: /tmp/bench/after /tmp/bench/test6.php
Time (mean ± σ): 770.8 ms ± 5.8 ms [User: 766.6 ms, System: 2.9 ms]
Range (min … max): 765.3 ms … 785.8 ms 10 runs
Summary
/tmp/bench/after /tmp/bench/test6.php ran
1.06 ± 0.01 times faster than /tmp/bench/before /tmp/bench/test6.php
This adds a new flag: ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC. When the flag is set,
zend_jit_dump_exit_info() exposes the source of exit points, in debug builds.
Closes GH-19700