The AutoValue concept is extremely simple: You write an abstract class, and AutoValue implements it.
Note: Below, we will illustrate an AutoValue class without a generated builder class. If you're more interested in the builder support, continue reading at AutoValue with Builders instead.
Create your value class as an abstract class, with an abstract accessor method
for each desired property, an equals method, and bearing the @AutoValue
annotation.
/**
* @AutoValue
*/
abstract class Animal
{
static function create(string $name, int $numberOfLegs): self
{
return new AutoValue_Animal([
'name' => $name,
'numberOfLegs' => $numberOfLegs,
]);
}
abstract function name(): string;
abstract function numberOfLegs(): int;
abstract function equals($value): bool;
}
Note that in real life, some classes and methods would presumably have PHPDoc. We're leaving these off in the User Guide only to keep the examples clean and short.
Install AutoValue in your project using Composer.
composer require space48/auto-value --dev
Note that AutoValue should be installed as a dev dependency as it does not need to be loaded in your project at runtime.
Your choice to use AutoValue is essentially API-invisible. That means that to the consumer of your class, your class looks and functions like any other. The simple test below illustrates that behavior. Note that in real life, you would write tests that actually do something interesting with the object, instead of only checking field values going in and out.
public function testAnimal() {
$dog = Animal::create('dog', 4);
self::assertEquals('dog', $dog->name());
self::assertEquals(4, $dog->numberOfLegs());
// You probably don't need to write assertions like these; just illustrating.
self::assertTrue(Animal::create('dog', 4)->equals($dog));
self::assertFalse(Animal::create('cat', 4)->equals($dog));
self::assertFalse(Animal::create('dog', 2)->equals($dog));
self::assertFalse(Animal::create('dog', 2)->equals('banana'));
}
When you create a new class bearing the @AutoValue
annotation, or modify or
remove such a class, you must run AutoValue's build command in order to rebuild
the AutoValue classes.
vendor/bin/auto build path/to/project/src
AutoValue searches the specified source directory for any abstract PHP classes
bearing the @AutoValue
annotation. It reads your abstract class and infers
what the implementation class should look like. It generates source code, in
your package, of a concrete implementation class which extends your abstract
class, having:
- one property for each of your abstract accessor methods
- a constructor that sets these fields
- a concrete implementation of each accessor method returning the associated property value
- an
equals
implementation that compares these values in the usual way
Your hand-written code, as shown above, delegates its factory method call to the generated constructor and voilà!
For the Animal
example shown above, here is typical code AutoValue might
generate.
Note that consumers of your value class don't need to know any of this. They just invoke your provided factory method and get a well-behaved instance back.
See Why AutoValue?.
How do I...
- ... also generate a builder for my value class?
- ... include
with-
methods on my value class for creating slightly altered instances? - ... use (or not use) JavaBeans-style name prefixes?
- ... use nullable properties?
- ... perform other validation?
- ... use a property of a mutable type?
- ... use a custom implementation of
equals
, etc.? - ... have multiple
create
methods, or name it/them differently? - ... ignore certain properties in
equals
, etc.? - ... have AutoValue also implement abstract methods from my supertypes?
- ... also include setter (mutator) methods?
- ... have one
@AutoValue
class extend another? - ... keep my accessor methods private?
- ... expose a constructor, not factory method, as my public creation API?
- ... use AutoValue on an interface, not abstract class?
- ... memoize ("cache") derived properties?