Fleshgrinder/php-core

View on GitHub
README.md

Summary

Maintainability
Test Coverage
[![Latest Stable Version](https://poser.pugx.org/fleshgrinder/core/v/stable)](https://packagist.org/packages/fleshgrinder/core)
[![License](https://poser.pugx.org/fleshgrinder/core/license)](https://packagist.org/packages/fleshgrinder/core)
[![Travis CI build status](https://img.shields.io/travis/Fleshgrinder/php-core.svg)](https://travis-ci.org/Fleshgrinder/php-core)
[![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/u5fbfnf7m3ws8l1b/branch/master?svg=true)](https://ci.appveyor.com/project/Fleshgrinder/php-core/branch/master)

[![Coveralls branch](https://img.shields.io/coveralls/Fleshgrinder/php-core/master.svg)](https://coveralls.io/github/Fleshgrinder/php-core)
[![Scrutinizer](https://img.shields.io/scrutinizer/g/Fleshgrinder/php-core.svg)](https://scrutinizer-ci.com/g/Fleshgrinder/php-core/)
[![Code Climate: GPA](https://img.shields.io/codeclimate/github/Fleshgrinder/php-core.svg)](https://codeclimate.com/github/Fleshgrinder/php-core)
[![Total Downloads](https://poser.pugx.org/fleshgrinder/core/downloads)](https://packagist.org/packages/fleshgrinder/core)
# Core
The **core** library provides the most basic functionality that is missing in
 PHP core (and most probably will never make it into it): helpers (in form of
 traits) to disable default PHP object behavior.

- [Installation](#installation)
- [Usage](#usage)
- [Testing](#testing)

## Installation
Open a terminal, enter your project directory and execute the following command
 to add this package to your dependencies:

```bash
composer require fleshgrinder/core
```

This command requires you to have Composer installed globally, as explained in
 the [installation chapter](https://getcomposer.org/doc/00-intro.md) of the
 Composer documentation.

## Usage
### Disenchant
The [Disenchant](src/Disenchant.php) trait can be used to disable support for
 the magic `__get`, `__isset`, `__set`, and `__unset` methods. Every object in
 PHP by default supports these methods for dynamic property management. However,
 these are features that are actually undesired in almost all situations. While
 support for them does not lead to serious bugs, it can result in in weird
 behavior. Especially in the case of value objects when equality is determined
 with PHP’s equality operator (`==`).

Suppose we have a simple value object:

```php
final class ValueObject {
    private $value;
    public function __construct($value) {
        $this->value = $value;
    }
}
```

Using the equality operator to determine if two instances are equal or not is
 straight forward, the same is true for comparisons:

```php
$v0 = new ValueObject(0);
$v1 = new ValueObject(1);

var_dump(
    $v0 < $v1,  // true
    $v0 <= $v1, // true
    $v0 == $v1, // false
    $v0 >= $v1, // false
    $v0 > $v1   // false
);
```

If we now add a property to `$v0` the result will be different:

```php
$v0 = new ValueObject(0);
$v0->x = 42;
$v1 = new ValueObject(1);

var_dump(
    $v0 < $v1,  // false
    $v0 <= $v1, // false
    $v0 == $v1, // false
    $v0 >= $v1, // true
    $v0 > $v1   // true
);
```

Of course, these operators should not be used and instead specialized
 functionality like [Equalable](https://github.com/fleshgrinder/php-equalable)
 and [Comparable](https://github.com/fleshgrinder/php-comparable) should be
 used, but this trait adds another layer of safety to the whole program at
 almost no cost.

Other situations in which this trait is very handy is if your objects rely on
 the properties they have. For instance if `get_object_vars` is used somewhere.
 However, note that not all possibly weird behavior is fixed through the
 inclusion of this trait. It is, for instance, still possible to dynamically
 add properties via specially crafted `unserialize` strings. This is because
 PHP does not call any of these magic methods in that case but directly adds
 the properties to the object, validate your objects in your `__wakeup` or
 `unserialize` methods instead.

### Uncloneable
The [Uncloneable](src/Uncloneable.php) trait can be used to disable support for
 the `clone` keyword in client code. This is a good idea for objects that
 cannot be cloned for technical reasons, e.g. anything that encloses a
 resource of some kind like a database connection, or should not be cloned
 because it makes no sense, e.g. any kind of immutable implementation like
 value objects.

The magic `__clone` method is defined as _final_ and _protected_ in this trait,
 this ensures that subclasses of the class that uses the trait are not able to
 alter that contract. At the same time it allows the using class to use the
 clone functionality internally to provide copy-on-write support without
 breaking changes; as illustrated in the following example:

```php
final class URI {
    use Fleshgrinder\Core\Uncloneable;

    // ...

    public function withFragment(string $fragment): URI {
        $clone = clone $this;
        $clone->fragment = $fragment;
        return $clone;
    }
}
```

Another interesting use-case are friend classes paired with the builder pattern
 to provide immutable entities.

```php
abstract class EntityFriend {
    use Fleshgrinder\Core\Uncloneable;

    protected $value;

    protected function setValue(T $value): void {
        $this->value = $value;
    }
}

final class Entity extends EntityFriend {
    public function getValue(): T {
        return $this->value;
    }
}

final class EntityBuilder extends EntityFriend {
    private $entity;

    public function __construct() {
        $this->entity = new Entity;
    }

    public function build(): Entity {
        return clone $this->entity;
    }

    public function setValue(T $value): void {
        $this->entity->setValue($value);
    }
}
```

### Unconstructable
The [Unconstructable](src/Unconstructable.php) trait can be used to disable
 support for the `new` keyword in client code. This is almost always a good
 idea to [disable multiple constructor calls](https://wiki.php.net/rfc/disallow-multiple-constructor-calls)
 and enforce invariance for actual constructor method arguments. Of course, the
 class requires named constructors, otherwise construction would be impossible.

```php
final class SomeClass {
    use Fleshgrinder\Core\Unconstructable;

    public static function new(): self {
        return new static;
    }
}
```

Another use-case are _final abstract_ classes, which are not available in PHP.

```php
final class AbstractFinalClass {
    use Fleshgrinder\Core\Unconstructable;

    public static function f() { }

    public static function f′() { }

    // ...
}
```

### Immutable
The [Immutable](src/Immutable.php) is a combination of all other traits, and
 is provided for convenience only. It is best used for any kind of immutable
 class, as the name already suggests.

## Testing
Open a terminal, enter the project directory and execute the following commands
 to run the [PHPUnit](https://phpunit.de/) tests with your locally installed
 PHP executable.

```bash
make
```

You can also execute the following two commands, in case `make` is not
 available on our system:

```bash
composer install
composer test
```