Releases: hhvm/type-assert
Support HHVM 3.24, require HHVM 3.23+
v3.2.0 Target HHVM 3.23+
Support for HHVM 3.23
This supports the upcoming HHVM 3.23 release, including the new shape behavior.
The previous behavior is retained if running HHVM 3.22.
Update HSL dependency to v1.0
No other changes.
Improved support for value types with Container, Traversable, KeyedContainer, KeyedTraversable
Some values (not objects) such as PHP and Hack Arrays are valid Containers and Traversables - however, these magic interfaces are not supported for values by is_a()
:
hphpd> =[123] instanceof Traversable
true
hphpd> ='123' instanceof Stringish
true
hphpd> =is_a([123], Traversable::class)
false
hphpd> =is_a('123', Stringish::class)
false
This led to TypeAssert incorrectly throwing exceptions when using matches_type_structure()
with these interfaces.
Traversable, KeyedTraversable, Container, and KeyedContainer are now special-cased to handle PHP arrays and Hack Arrays. Thanks again to @genych for the report.
Improved support for Traversable and related interfaces
Supports Traversable, Container, KeyedTraversable, KeyedContainer; thanks to @genych for the report.
In general, generics can not be validated - but support for specific classes and interfaces can be added.
This support only applies to container-like implementations; it will throw an UnsupportedTypeException
if you attempt to validate any other implementation, as they might not be rewindable; validating the values of a non-rewindable traversable (such as a generator) would make it unusable.
More liberal dependency requirements
v3.0.1 update dependency requirements
Namespaces, coercion, nested types, and error message improvements
- For consistency with the Hack Standard Library, all functionality has moved from static methods to namespaced functions; for example,
TypeAssert::isInt()
is nowTypeAssert\int()
- Hack Arrays (vec/dict/keyset) are now supported
- Added support for coercion in the
Facebook\TypeCoerce
namespace - Added support for complex types without type structures as
Facebook\TypeSpec
- Error messages now include debugging information for nested types
- Function autoloading is now required; hhvm-autoload is recommended
- HHVM 3.21 or newer is now required; if you are unable to upgrade yet and require bug fixes in the 2.x series on HHVM 3.18, please file an issue. New features such as coercion and hack array support will not be back ported, and 3.18 will become unsupported when HHVM 3.24 is released.
Coercion
The coercion attempts to only do safe, unambiguous conversions - it does not aim to follow PHP's semantics; for example, if a string contains characters other than 0-9, TypeCoerce will throw an exception, however PHP coercion accepts some other strings.
Example
<?hh
use namespace Facebook\{TypeAssert, TypeCoerce};
$x = TypeCoerce\int(123.0); // $x is now int(123)
$x = TypeAssert\int(123.0); // throws an exception, $x is not an int
$x = TypeCoerce\string('123'); // $x is now int(123);
$x = TypeCoerce\string('1e123'); // throws an exception: unclear if this is 1x10^123, or hexadecimal
TypeSpec
TypeSpec allows you to specify a complex type without using type structures. Nested types are supported, however types such as shapes and tuples that can not be generically expressed in Hack are not.
Example
<?hh
use namespace Facebook\TypeSpec;
// TypeSpec for dict<string, int>
$spec = TypeSpec\dict(
TypeSpec\string(),
TypeSpec\int(),
);
$x = $spec->assertType(dict['foo' => 123]); // no change
$x = $spec->coerceType(dict['foo' => '123']); // returns dict['foo' => 123]
$x = $spec->coerceType(Map { 'foo' => '123' }); // returns dict['foo' => 123]
$x = $spec->assertType(Map { 'foo' => 123 }); // throws an exception
Error Messages
We've made it easier to debug type mismatches in nested structures by including traces.
Example
<?hh
require('vendor/hh_autoload.php');
use namespace Facebook\TypeAssert;
class Foo {
const type TShape = shape(
'foo' => string,
'bar' => shape(
'baz' => int,
),
);
const type TDict = dict<string, self::TShape>;
public function main(): void {
$shape = shape(
'foo' => 'herp',
'bar' => shape(
'baz' => 'derp',
),
);
$dict = dict['shape' => $shape];
TypeAssert\matches_type_structure(
type_structure(self::class, 'TDict'),
$dict,
);
}
}
$ hhvm test.php
Fatal error: Uncaught exception 'Facebook\TypeAssert\IncorrectTypeException' with message 'Expected type 'int', got type 'string'
Type trace:
#0 shape[baz]
#1 shape[bar]
#2 dict<_, Tv>
'
Facebook namespace and license
- relicense: Type-Assert is BSD-licensed. We also provide an additional patent grant.
- namespace changed from
FredEmmott\TypeAssert
toFacebook\TypeAssert
- composer package name changed from
fredemmott/type-assert
tohhvm/type-assert
Fix `matches_type_structure()` where a shape should contain a container, but doesn't
Code like this would raise a fatal error:
class A
{
const type Something = shape('ints' => Container<int>);
}
\FredEmmott\TypeAssert\TypeAssert::matchesTypeStructure(
type_structure(A::class, 'Something'), []);
This now throws an IncorrectTypeException
; thanks to @genych for reporting.
Support for HHVM 3.18
No other significant changes.