Skip to content

1.2.0

Latest

Choose a tag to compare

@Jeckerson Jeckerson released this 27 Jul 23:15
d795c01

Added

  • Added the ::class magic constant: self::class, parent::class and ClassName::class resolve to the fully-qualified class name at compile time, and static::class resolves to the called class at runtime (late static binding) #2527
  • Trait properties can now have array default values (e.g. trait T { public opts = [1, 2, 3]; }, including empty, keyed and nested arrays). The default is materialized as a persistent immutable array on the trait's class entry, so it is carried into both Zephir classes and PHP userland classes that use the trait, matching native PHP trait semantics. Static array defaults on traits remain rejected (Zephir resolves self:: in a trait to the trait itself, so each using class could not get its own copy) #2607
  • Class and trait properties can now declare a type, mirroring PHP's typed properties: builtin (int, bool, double, string, array, object), nullable (?string), and class types (<My\Class>, ?<My\Class>). The type is emitted via zend_declare_typed_property, so Reflection reports it and the engine enforces it; a typed property with no default is uninitialized (public <Foo> conn;) rather than null, matching PHP #2608
  • Added union types (int | float) on method/function parameters and class/trait properties (e.g. public int|float foo;, function f(float|int bar) -> int|float). Reflection reports a ReflectionUnionType; union properties are engine-enforced on write (scalar, null/false, and one or more <Class> members), while a union parameter binds as a mixed value carrying its declared arg-info type mask. Union return types were already supported #2613
  • Added readonly properties (e.g. public readonly array foo): the property carries ZEND_ACC_READONLY, so Reflection reports it and the engine enforces write-once after initialization. Like PHP, a readonly property must be typed, cannot declare a default value and cannot be static (each rejected at compile time). Enforced on PHP 8.1+; on PHP 8.0 it degrades to a plain typed property #2614
  • Added the += (add-assign) operator on arrays, performing PHP array union (let a += [1, 2]), for array literals and both array-typed and untyped var operands #1280
  • Added an opt-in missing-optimizer warning that reports function calls with no applicable optimizer, which are dispatched by name through the Zend function table at runtime instead of being inlined. It also covers calls an existing optimizer declined because it does not handle that call form (e.g. count(a, 0)), which are otherwise invisible. Enable with -wmissing-optimizer; each function is reported once per run, at its first call site #2468
  • Added a --with-php-config=PATH option to the build, compile and fullclean commands, so an extension can be built against a PHP installation other than the one in the PATH (e.g. a separate ZTS build). phpize is taken from the same directory as the given php-config, and an unusable or mismatched path is rejected before the build starts. Not available on Windows, where the dev-pack (%PHP_DEVPACK%) selects the target PHP #1834

Fixed

  • Fixed char/uchar values in dynamic (zval) contexts. A string offset read (s[i]) now boxes as a 1-character string when its target is a var/string variable or an array element, matching PHP's $s[$i]: string ch; let ch = s[i]; used to emit C that did not compile, and let pieces[] = s[i]; was rejected with Unknown type: uchar. A declared char/uchar variable still boxes as its integer byte value (as let a = [ch] and return ch already did) — use (string) ch for the character — and a direct return s[i] is unchanged #1629
  • char/uchar are now accepted in the remaining scalar positions, each of which previously threw or emitted invalid C: (uchar) casts, (string)/(char) casts of a uchar, uchar method parameters and globals, keyed array literals ([1: ch]), let a[k] = ch, object and static property array offsets, and double/bool targets. A char literal reaching a numeric slot no longer emits ZVAL_LONG(&x, ''a''), and assigning an int to a string (string s; let s = i;) no longer emits dead PHP-5 code #1629
  • Fixed acos() and asin() never using their optimizers on case-sensitive filesystems: optimizer lookup derives AcosOptimizer.php/AsinOptimizer.php from the function name, but the files were named ACosOptimizer.php/ASinOptimizer.php, so both calls compiled to a runtime function call on Linux while macOS and Windows inlined them #2468
  • Fixed typed-property and array-class-constant string defaults containing escape sequences (e.g. protected string x = "A\\B\\C") being emitted with the wrong byte length: the length was strlen() of the source-escaped PHP value (a \\ counted as two bytes) while the C string literal is shorter, so the runtime string was over-long and corrupted with trailing garbage bytes. The length is now measured by the C compiler (SL() / sizeof), correct for every escape sequence #2617
  • Fixed the Zephir version has changed warning firing on every rebuild: the version-cache directory existence check used is_file() on a path that is always a directory, so the check never matched and the warning degraded to "warn whenever the project was already built". It now fires only on a genuine version change and names the old and new versions #2621