Download the PHP package wwwision/types without Composer

On this page you can find all versions of the php package wwwision/types. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package types

Library to narrow the scope of your PHP types with JSON Schema inspired attributes allowing for validating and mapping unknown data.

Why this package might be for you Why this package might NOT be for you
Extends the PHP type system Uses reflection at runtime (see performance considerations)
Great integrations Partly unconventional best practices
Simple Generics Static class, i.e. global (namespaced) instantiate() method
No need to implement interfaces or extend base classes Very young project – I certainly would be skeptical if I hadn't written this myself ;)
Small footprint (just one public function/class and a couple of 3rd party dependencies) You just don't like me.. pff.. whateva

Usage

This package can be installed via composer:

Afterward, three steps are required to profit from the type safety of this package.

Given, you have the following Contact entity:

This class has a couple of issues:

0. Create classes for your Value Objects

Note This list is 0-based because that part is slightly out of scope, it is merely a general recommendation

1. Add attributes

By adding one of the provided attributes, schema information and documentation can be added to type classes:

Note In most cases it makes sense to specify an upper bound for your types because that allows you to re-use that at "the edges" (e.g. for frontend validation and database schemas)

2. Make constructor private and classes immutable

By making constructors private, validation can be enforced providing confidence that the objects don't violate their allowed range. See best practices for more details.

3. Use instantiate() to create instances

With private constructors in place, the instantiate() function should be used to create new instances of the affected classes:

Note In practice you'll realize that you hardly need to create new Entity/Value Object instances within your application logic but mostly in the infrastructure layer. E.g. a DatabaseContactRepository might return a Contacts object.

Example: Database integration

Best practices

In order to gain the most with this package, a couple of rules should be considered:

All state fields in the constructor

This package uses reflection to parse the constructors of involved classes. Therefore the constructor should contain every variable that makes up the internal state (IMO that's a good practice anyways). In general you should only allow state changes through the constructor and it's a good idea to mark DTO classes as readonly

Private constructors

In order to allow data to be validated everywhere, there must be no way to instantiate an ListBased class other than with the provided instantiate() method.

Therefore, constructors of Value Objects should be private:

Note For Shapes (i.e. composite) objects that rule doesn't apply, because all of their properties are valid if the above rule is followed:

Final classes

In my opinion, classes in PHP should be final by default. For the core domain types this is especially true because inheritance could lead to invalid schemas and failing validation. Instead, composition should be used where it applies.

Immutability

In order to guarantee the correctness of the types, there should be no way to change a value without re-applying validation. The easiest way to achieve this, is to make those types immutable – and this comes with some other benefits as well.

The readonly keyword can be used on properties (with PHP 8.2+ even on the class itself) to ensure immutability on the PHP type level.

If types should be updatable from the outside, ...

Attributes

Description

The Description attribute allows you to add some domain specific documentation to classes and parameters.

Example: Class with description

IntegerBased

With the IntegerBased attribute you can create Value Objects that represent an integer. It has the optional arguments

Example

FloatBased

Starting with version 1.2

With the FloatBased attribute you can create Value Objects that represent a floating point number (aka double). It has the optional arguments

Example

StringBased

With the StringBased attribute you can create Value Objects that represent a string. It has the optional arguments

Example: String Value Object with min and max length constraints
Example: String Value Object with format and pattern constraints Just like with JSON Schema, `format` and `pattern` can be _combined_ to further narrow the type:

ListBased

With the ListBased attribute you can create generic lists (i.e. collections, arrays, sets, ...) of the specified itemClassName. It has the optional arguments

Example: Simple generic array
Example: More verbose generic array with type hints and min and max count constraints The following example shows a more realistic implementation of a List, with: * An `@implements` annotation that allows IDEs and static type analyzers to improve the DX * A [Description](#description) attribute * `minCount` and `maxCount` validation * `Countable` and `JsonSerializable` implementation (just as an example, this is not required for the validation to work)

Composite types

The examples above demonstrate how to create very specific Value Objects with strict validation and introspection.

Example: Complex composite object

Generics

Generics won't make it into PHP most likely (see this video from Brent that explains why that is the case).

The ListBased attribute allows for relatively easily creation of type-safe collections of a specific item type.

Currently you still have to create a custom class for that, but I don't think that this is a big problem because mostly a common collection class won't fit all the specific requirements. For example: PostResults could provide different functions and implementations than a Posts set (the former might be unbound, the latter might have a minCount constraint etc).

Further thoughts

I'm thinking about adding a more generic (no pun intended) way to allow for common classes without having to specify the itemClassName in the attribute but at instantiation time, maybe something along the lines of

But it adds some more oddities and I currently don't really need it becaused of the reasons mentioned above.

Interfaces

Starting with version 1.1, this package allows to refer to interface types.

In order to instantiate an object via its interface, the instance class name has to be specified via the __type key. All remaining array items will be used as usual. For simple objects, that only expect a single scalar value, the __value key can be specified additionally:

Especially when working with generic lists, it can be useful to allow for polymorphism, i.e. allow the list to contain any instance of an interface:

Example: Generic list of interfaces

Error handling

Errors that occur during the instantiation of objects lead to an InvalidArgumentException to be thrown. That exception contains a human-readable error message that can be helpful to debug any errors, for example:

Failed to instantiate FullNames: At key "0": At property "givenName": Value "a" does not have the required minimum length of 3 characters

Starting with version 1.2, the more specific CoerceException is thrown with an improved exception message that collects all failures:

Failed to cast value of type array to FullNames: At "0.givenName": too_small (String must contain at least 3 character(s)). At "1.familyName": invalid_type (Required)

In addition, the exception contains a property issues that allows for programmatic parsing and/or rewriting of the error messages. The exception itself is JSON-serializable and the above example would be equivalent to:

Note If the syntax is familiar to you, that's no surpise. It is inspired (and in fact almost completely compatible) with the issue format of the fantastic Zod library

Integrations

The declarative approach of this library allows for some interesting integrations. So far, the following two exist – Feel free to create another one and I will gladly add it to this list:

Dependencies

This package currently relies on the following 3rd party libraries:

...and has the following DEV-requirements:

Performance

This package uses Reflection in order to introspect types. So it comes with a performance hit. Fortunately the performance of Reflection in PHP is not as bad as its reputation and while you can certainly measure a difference, I doubt that it will have a notable effect in practice – unless you are dealing with extremely time critical applications like realtime trading in which case you should not be using PHP in the first place... And you should probably reconsider your life choices in general :)

Nevertheless, this package contains a runtime cache for all reflected classes. So if you return a huge list of the same type, the performance impact should be minimal. I am measuring performance of the API via PHPBench to avoid regressions, and I might add further caches if performance turns out to become an issue.

Contribution

Contributions in the form of issues, pull requests or discussions are highly appreciated

License

See LICENSE


All versions of types with dependencies

PHP Build Version
Package Version
Requires php Version >=8.1
webmozart/assert Version ^1.11
ramsey/uuid Version ^4.7
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package wwwision/types contains the following files

Loading the files please wait ....