PHPackages                             jesseschalken/magic-utils - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. jesseschalken/magic-utils

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

jesseschalken/magic-utils
=========================

Traits and functions to help with implementing PHP's magic methods

0.2(10y ago)129MITPHP

Since Dec 20Pushed 10y ago1 watchersCompare

[ Source](https://github.com/jesseschalken/php-magic-utils)[ Packagist](https://packagist.org/packages/jesseschalken/magic-utils)[ RSS](/packages/jesseschalken-magic-utils/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (2)Dependencies (1)Versions (3)Used By (0)

php-magic-utils
===============

[](#php-magic-utils)

**php-magic-utils** provides traits and functions to help with the implementation of [PHP's magic methods](http://php.net/manual/en/language.oop5.magic.php), especially `__clone()`.

MethodDefaultDisallow`__construct()`*nothing*, construction allowed`use NoConstruct;``__destruct()`*nothing*`__call()`, `__callStatic()``Fatal error: Call to undefined method $class::$method()``use NoDynamicMethods;``__get()`, `__set()`, `__isset()`, `__unset()`*Write:* Create undeclared public properties (!)
*Read:* `Undefined property: $class::$property``use NoDynamicProperties;``__sleep()`, `__wakeup()`*nothing*, `serialize()`/`unserialize()` allowed`use NoSerialize;``__toString()``Catchable fatal error: Object of class $class could not be converted to string``__invoke()``Fatal error: Function name must be a string``__set_state()``Fatal error: Call to undefined method $class::__set_state()``__clone()`shallow clone (for deep clone use `use DeepClone;`)`use NoClone;``__debugInfo()``var_dump()` prints all public properties### `use DeepClone;`

[](#use-deepclone)

`DeepClone` turns

```
class Foo extends Bar {
    /** @var Blah|null */
    private $blah;
    /** @var \DateTime[] */
    private $dates = [];

    // :( :( :(
    function __clone() {
        parent::__clone();

        if ($this->blah !== null)
            $this->blah = clone $this->blah;

        foreach ($this->dates as $k => $date)
            $this->dates[$k] = clone $date;
    }
}
```

into

```
class Foo extends Bar {
    /** @var Blah|null */
    private $blah;
    /** @var \DateTime[] */
    private $dates = [];

    // :) :) :)
    use DeepClone;
}
```

It implements `__clone()` by calling `parent::__clone()` if it exists, and cloning all objects contained in all properties of the class in which it's used, including objects in arbitrarily nested arrays. It will error if it finds a `resource` type, since `resource`s are pass-by-reference like objects and therefore should be cloned, but there is no general way to clone a `resource`.

Note that you have to use `use DeepClone;` at each level in a class hierarchy. It will not clone properties of parent or derived classes.

#### Why do a deep clone?

[](#why-do-a-deep-clone)

When an object is cloned with `clone ...`, PHP by default does a *shallow* clone, meaning a new object is created with the same value for all properties, but sharing the same instance of any objects contained in those properties. This can expose the user of the class to be affected by what information is stored directly and what information is stored indirectly through other objects, breaking abstraction and causing subtle bugs.

Here is an example:

```
class A {
    private $foo = 9;
    public function getFoo() { return $this->foo; }
    public function setFoo($foo) { $this->foo = $foo; }
}
```

```
function test() {
    $a1 = new A;
    $a1->setFoo(100);
    $a2 = clone $a1;
    $a2->setFoo(200);
    print $a1->getFoo(); // 100
}
```

If an innocent refactoring is made to move the value of the `$foo` property into another object (`B`):

```
class A {
    private $b;
    public function __construct() {
        $this->b = new B;
    }
    public function getFoo() { return $this->b->foo; }
    public function setFoo($foo) { $this->b->foo = $foo; }
}

class B {
    public $foo = 9;
}
```

The `test()` function will now print *200* instead of *100*, because both `$a1` and `$a2` will share the same instance of `B`.

This can be resolved by implementing `__clone()` by doing a deep clone:

```
class A {
    private $b;
    // ...
    public function __clone() {
        $this->b = clone $this->b;
    }
    // ...
}
```

The developer making the refactoring has to rememeber to keep the `__clone()` method up to date to maintain behaviour in case the object is cloned. `use DeepClone;` does this for you, so you don't have to remember.

### `clone_ref(mixed &$x):void`

[](#clone_refmixed-xvoid)

Will clone all objects contained in the specified variable, including those inside nested arrays. It is useful for implementing `__clone()` by deep cloning only some properties.

For example:

```
class A {
    private $prop1;
    private $prop2;
    function __construct() {
        $this->prop1 = new Foo1;
        $this->prop2 = new Foo2;
    }
    function __clone() {
        clone_ref($this->prop2);
        // cloned instances will share the same object stored in $this->prop1
    }
}
```

### `clone_val(mixed $x):mixed`

[](#clone_valmixed-xmixed)

Will clone all objects contained in the specified value, and return the new value.

### `use NoClone;`

[](#use-noclone)

`use NoClone;` prevents an object from being cloned. It implements `__clone()` by throwing a `CloneNotSupportedException`.

### `use NoDynamicMethods;`

[](#use-nodynamicmethods)

The magic methods `__call()` and `__callStatic()` make adding new methods to a class potentially unsafe, since the new method may unintentionally override a dynamic method handled by `__call()` or `__callStatic()`.

`use NoDynamicMethods;` defines `__call()` and `__callStatic()` to throw an `UndefinedMethodException`, so adding new methods is always safe.

### `use NoDynamicProperties;`

[](#use-nodynamicproperties)

The magic methods `__get()`, `__set()`, `__isset()` and `__unset()` make adding new properties to a class potentially unsafe, since the new property may unintentionally override a dynamic property handled by these magic methods.

Even without these magic methods defined, a new property on a class may already be being used as an undeclared public property, for example:

```
class Foo {
}
```

```
function blah(Foo $foo) {
    $foo->bar = 5;
    return $foo->bar;
}
```

The usage of a undeclared property `Foo::$bar` in `blah()` has made it unsafe for the author of `Foo` to add `Foo::$bar` as a new property.

`use NoDynamicProperties;` defines `__get()`, `__set()`, `__isset()` and `__unset()` to throw an `UndefinedPropertyException`, so adding new properties is always safe.

### `use NoSerialize;`

[](#use-noserialize)

PHP's builtin `serialize()` and `unserialize()` functions make it potentially unsafe to change a class's name or properties, because a serialized version of the class may exist which needs to continue to work when unserialized.

`use NoSerialize;` defines `__sleep()` and `__wakeup()` to throw a `SerializeNotSupportedException` so renaming a class or changing its properties is always safe.

### `use NoMagic;`

[](#use-nomagic)

`use NoMagic;` disallows any magic which makes refactoring difficult. It is equivalent to

```
use NoDynamicMethods;
use NoDynamicProperties;
use NoSerialize;
```

###  Health Score

25

—

LowBetter than 36% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~13 days

Total

2

Last Release

3831d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1559204?v=4)[Jesse Schalken](/maintainers/jesseschalken)[@jesseschalken](https://github.com/jesseschalken)

---

Top Contributors

[![jesseschalken](https://avatars.githubusercontent.com/u/1559204?v=4)](https://github.com/jesseschalken "jesseschalken (43 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jesseschalken-magic-utils/health.svg)

```
[![Health](https://phpackages.com/badges/jesseschalken-magic-utils/health.svg)](https://phpackages.com/packages/jesseschalken-magic-utils)
```

###  Alternatives

[andreas-glaser/php-helpers

A comprehensive collection of PHP utility functions for array manipulation, string operations, date handling, HTML generation, form building, validation, and more. Modern PHP 8.2+ library with full type safety.

1387.6k2](/packages/andreas-glaser-php-helpers)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
