immutable/immutable

v1.0.2 2017-10-29 14:07 UTC

This package is not auto-updated.

Last update: 2024-05-02 17:29:03 UTC


README

CircleCI

Introduction

An Immutable object is an object that can not be changed once it is created.

Using Immutable object makes it unnecessary to clone an object for precaution in order to avoid unintentional object changes, so the code is simple.

Normally, there is a need to design a class so that it becomes Immutable from the beginning, but if you use Immutable, you can easily make an existing object Immutable.

Easy to use

Using composer, it can be implemented very easily.

composer require immutable/immutable

Immutable

Immutable objects are created from existing objects or arrays.

If an array is used, it is internally converted to \ stdClass.

Even if you change to Immutable object, you can use all public methods and properties.

In addition, even when using a private (or protected) method or property in a public method, it also works.

A simple example

With Immutable, Immutable objectization is very easy.

The following example imtutables a DateTime object.

<?php

require 'vendor/autoload.php';

use Immutable\Immutable;

$DT = new DateTime('2017-10-09 12:20:30');

// Immutable objectization 
$DT = Immutable::freeze($DT);

echo $DT->format('Y-m-d H:i:s');
// 2017-10-09 12:20:30

$DT->modify('+10 day');

echo $DT->format('Y-m-d H:i:s');
// 2017-10-09 12:20:30

ImmutableElement

If stdClass (or array) is Immutable object, it will eventually be converted as ImmutableElement.

ImmutableElement provides a simple API.

<?php
require 'vendor/autoload.php';

use Immutable\ImmutableElement;

$element1 = new ImmutableElement(['a' => 1, 'b' => 2, 'c' => 3, ]);
$element2 = $element1->set('b', 100);
echo $element1->get('b');
// 2

// Or do as follows...
echo $element1->b;
// 2

echo $element2->get('b');
// 100

// Or do as follows...
echo $element2->b;
// 100

Method Chain

If the original object is using a method chain, create a new Immutable object with changes in Method added.

require 'vendor/autoload.php';

use Immutable\Immutable;

$DT = new DateTime('2017-10-09 12:20:30');

// Immutable objectization 
$DT = Immutable::freeze($DT);

echo $DT->format('Y-m-d H:i:s');
// 2017-10-09 12:20:30

// A new Immutable object that is + 10 days is substituted for $DT2.
$DT2 = $DT->modify('+10 day');
echo $DT2->format('Y-m-d H:i:s');
// 2017-10-19 12:20:30

// With a method chain.
echo $DT->modify('+10 day')->format('Y-m-d H:i:s');
// 2017-10-19 12:20:30

// Immutable object does not change
echo $DT->format('Y-m-d H:i:s');
// 2017-10-09 12:20:30

Recursive Immutable

When Immutable an array or stdClass, you would want to recursively make all child elements Immutable.

A mechanism for that purpose is also prepared.

The following example is an example of recursively Immutable multidimensional associative array.

require 'vendor/autoload.php';

use Immutable\Immutable;

$array_mutable = [['name' => 'Tanaka'], ['name' => 'Suzuki']];
$array_immutable = Immutable::freezeRecursive($array_mutable);

Mutable

It is also easy to return an immutable object to a mutable object.

A simple example

Mutable is also very simple. The following example restores the Imutableized DateTime object.

<?php

require 'vendor/autoload.php';

use Immutable\Immutable;

$DT = new DateTime('2017-10-09 12:20:30');

// Immutable objectization 
$DT = Immutable::freeze($DT);

// Some processing


// Mutable objectization 
$DT = Immutable::thaw($DT);

echo $DT->format('Y-m-d H:i:s');
// 2017-10-09 12:20:30

$DT->modify('+10 day');

echo $DT->format('Y-m-d H:i:s');
// 2017-10-19 12:20:30

instanceOf

Immutable objects are naturally objects different from mutable objects, so you can not examine them with the native instanceof operator.

It shows an alternative means for that.

Example using Immutable\Immutable::instanceOf()

Here is an example of using Immutable\Immutable::instanceOf() Method to make an instanceof judgment.

<?php
require 'vendor/autoload.php';

use Immutable\Immutable;

$DT = new DateTime('2017-10-09 12:20:30');

var_export(Immutable::instanceOf($DT, DateTime::class));
// true

var_export($DT instanceof DateTime);
// true

// Immutable objectization 
$DT = Immutable::freeze($DT);

//  class name obviously true
var_export(Immutable::instanceOf($DT, DateTime::class));
// true

// As with instanceof, even if you specify an impleted interface, it is true
var_export(Immutable::instanceOf($DT, DateTimeInterface ::class));
// true

// It is false for standard instanceof
var_export($DT instanceof DateTime);
// false


// Mutable objectization 
$DT = Immutable::thaw($DT);
var_export(Immutable::instanceOf($DT, DateTime::class));
// true

var_export($DT instanceof DateTime);
// true

How to create Immutable Instance class

By implementing a mutable class and a common interface in the Immutable class, which inherits from Immutable \ ImmutableInstance, You will be able to use native type hinting and instanceof.

<?php
require 'vendor/autoload.php';

use Immutable\Immutable;
use Immutable\ImmutableInstance;

interface DateTimeClassInterface
{
    public function subDay(int $int): DateTimeClassInterface;
}

class DateTimeInstance extends DateTime implements DateTimeClassInterface
{
    public function subDay(int $int) : DateTimeClassInterface
    {
        return $this->modify('+'.$int.' day');
    }
}

class DateTimeImmutableInstance extends ImmutableInstance implements DateTimeClassInterface
{
    public function subDay(int $int) : DateTimeClassInterface
    {
        // When implementing the contents of interface please describe all contents below
        return call_user_func_array([$this, '__call'], [__FUNCTION__, func_get_args()]);
    }
}



$DT = new DateTimeInstance('2017-10-09 12:20:30');

// Immutable (specify the class name with the second argument)
$DT = Immutable::freeze($DT, DateTimeImmutableInstance::class);

// Class name obviously true
var_export(Immutable::instanceOf($DT, DateTimeInstance::class));
// true

// As with instanceof, even if you specify an impleted interface, it is true
var_export(Immutable::instanceOf($DT, DateTimeClassInterface ::class));
// true

// Since Interface is common, it is true
var_export($DT instanceof DateTimeImmutableInstance);
// true

// Functions and methods with type hintings can also be used

function example(DateTimeClassInterface $instance)
{
    return 'ok';
}

echo example($DT);
// ok


// Implemented methods
var_export($DT->subDay(10)->format('Y-m-d H:i:s'));
// '2017-10-19 12:20:30'