Currently, classes that can't be linked get moved back into the original script
and are not preloaded. As such classes may be referenced from functions that
did get preloaded, there is a preload autoload mechanism to load them at
runtime.
Since PHP 8.1, we can safely preload unlinked classes, which will then go
through usual lazy loading. This means that we no longer need the preload
autoload mechanism. However, we need to be careful not to modify any hash
table buckets in-place, and should create new buckets for lazy loaded classes.
Convert zend_hash_find_ex(..., 1) to zend_hash_find_known_hash(...)
Convert zend_hash_find_ex(..., 0) to zend_hash_find(...)
Also add serializable changes to UPGRADING.INTERNALS summary
Add support for readonly properties, for which only a single
initializing assignment from the declaring scope is allowed.
RFC: https://wiki.php.net/rfc/readonly_properties_v2
Closes GH-7089.
Deprecate automatically converting "false" into an empty array
on write operands. Autovivification continues to be supported
for "null" values, as well as undefined/uninitialized values.
RFC: https://wiki.php.net/rfc/autovivification_false
Closes GH-7131.
Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
For a particular assignment, a non-coerced constant assignment
value will remain valid. However, opcache merges cache slots for
all identical property references, which means that this
optimization also disables property type checks for all other
operands on the property that occur in the same functions.
This could be addressed by blocking cache slot merging in opcache,
but I prefer dropping it entirely instead. It does not seem
important enough to warrant doing that.
Support acquiring a Closure to a callable using the syntax
func(...), $obj->method(...), etc. This is essentially a
shortcut for Closure::fromCallable().
RFC: https://wiki.php.net/rfc/first_class_callable_syntax
Closes GH-7019.
Co-Authored-By: Nikita Popov <nikita.ppv@gmail.com>
Static trait members may only be accessed through a class in which
the trait is used, not directly on the trait.
A complication here is that we should not store static
methods/properties for which a deprecation is triggered in a
cache slot. As the check for this is simple and cheap, I'm handling
this in the cache slot population code in the VM. The alternative
would be to pass the cache slot down into the fetching code.
Part of https://wiki.php.net/rfc/deprecations_php_8_1.
Now GDB correctly shows backtraces that involves JIT-ed code for
functional/tracing JIT, HYBRID/CALL VM, x86/AArch64 CPU.
(opcache.jit_debug=0x100 should be set).
The never type can be used to indicate that a function never
returns, for example because it always unwinds.
RFC: https://wiki.php.net/rfc/noreturn_type
Closes GH-6761.
This PR corrects misspellings identified by the check-spelling action.
The misspellings have been reported at jsoref@b6ba3e2#commitcomment-48946465
The action reports that the changes in this PR would make it happy: jsoref@602417c
Closes GH-6822.
We have separate flags for non-autoloading class fetches and
silent class fetches. There's no reason why NO_AUTOLOAD should
be special-cased to be implicitly silent.
If an internal class overrides read_property and declared property
types, make sure that the returned value matches the declared
type (in debug builds).
Currently, dynamically declared functions and closures are inserted
into the function table under a runtime definition key, and then later
possibly renamed. When opcache is not used and a file containing a
closure is repeatedly included, this leads to a very large memory leak,
as the no longer needed closure declarations will never be freed
(https://bugs.php.net/bug.php?id=76982).
With this patch, dynamic functions are instead stored in a
dynamic_func_defs member on the op_array, which opcodes reference
by index. When the parent op_array is destroyed, the dynamic_func_defs
it contains are also destroyed (unless they are stilled used elsewhere,
e.g. because they have been bound, or are used by a live closure). This
resolves the fundamental part of the leak, though doesn't completely
fix it yet due to some arena allocations.
The main non-obvious change here is to static variable handling:
We can't destroy static_variables_ptr in destroy_op_array, as e.g.
that would clear the static variables in a dynamic function when
the op_array containing it is destroyed. Static variable destruction
is separated out for this reason (we already do static variable
destruction separately for normal functions, so we only need to
handle main scripts).
Closes GH-5595.
zend_find_array_dim_slow() may throw, make sure to handle this.
This backports the code we already use for this on PHP-8.0,
and also backports an exception check that makes this easier to
catch.
When a method is inherited, the static variables will now always
use the initial values, rather than the values at the time of
inheritance. As such, behavior no longer depends on whether
inheritance happens before or after a method has been called.
This is implemented by always keeping static_variables as the
original values, and static_variables_ptr as the modified copy.
Closes GH-6705.
The C compiler sees that a dynamic function is being called, so it cannot infer
that iter->funcs has not changed.
This results in more assembly instructions and slightly more time to execute that code
path.
Unpacking traversables to arrays(`ZEND_ADD_ARRAY_UNPACK`),
starting foreach loops (`ZEND_FE_FETCH*`), etc. are affected.
```
<?php
/*
* Before: 1.576 seconds
* After: 1.474 seconds
*/
function example() {
$start = hrtime(true);
$it = new SplFixedArray(1000);
$total = 0;
for ($i = 0; $i < 100000; $i++) {
$total += count([...$it]);
}
$end = hrtime(true);
printf("Elapsed: %.6f\n", ($end - $start) / 1_000_000_000);
}
example();
```
This deprecates passing null to non-nullable scale arguments of
internal functions, with the eventual goal of making the behavior
consistent with userland functions, where null is never accepted
for non-nullable arguments.
This change is expected to cause quite a lot of fallout. In most
cases, calling code should be adjusted to avoid passing null. In
some cases, PHP should be adjusted to make some function arguments
nullable. I have already fixed a number of functions before landing
this, but feel free to file a bug if you encounter a function that
doesn't accept null, but probably should. (The rule of thumb for
this to be applicable is that the function must have special behavior
for 0 or "", which is distinct from the natural behavior of the
parameter.)
RFC: https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg
Closes GH-6475.
This is a new transparent technology that eliminates overhead of PHP class inheritance.
PHP classes are compiled and cached (by opcahce) separately, however their "linking" was done at run-time - on each request. The process of "linking" may involve a number of compatibility checks and borrowing methods/properties/constants form parent and traits. This takes significant time, but the result is the same on each request.
Inheritance Cache performs "linking" for unique set of all the depending classes (parent, interfaces, traits, property types, method types involved into compatibility checks) once and stores result in opcache shared memory. As a part of the this patch, I removed limitations for immutable classes (unresolved constants, typed properties and covariant type checks). So now all classes stored in opcache are "immutable". They may be lazily loaded into process memory, if necessary, but this usually occurs just once (on first linking).
The patch shows 8% improvement on Symphony "Hello World" app.