PHPackages                             perlucas/phpwrapper - 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. perlucas/phpwrapper

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

perlucas/phpwrapper
===================

A simple PHP set of wrappers for extending functionality

00PHP

Since Apr 10Pushed 6y ago1 watchersCompare

[ Source](https://github.com/perlucas/phpwrapper)[ Packagist](https://packagist.org/packages/perlucas/phpwrapper)[ RSS](/packages/perlucas-phpwrapper/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

A simple set of PHP wrappers for extending functionality
========================================================

[](#a-simple-set-of-php-wrappers-for-extending-functionality)

[![Generic badge](https://camo.githubusercontent.com/97f85f046265623c4b26076add9bcc55f9608152c20e78f07076369977c77d05/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d312e302e302d677265656e2e737667)](https://github.com/perlucas/phpwrapper) [![Generic badge](https://camo.githubusercontent.com/a0f6b8cd184f911a6fb0c889eeb497a0f329089c2349f885f253b71b486cb9a3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d2533453d352e342d677265656e2e737667)](https://github.com/perlucas/phpwrapper)

This library provides a set of generic wrapper classes that can be used for implementing Adapter, Proxy , Null Object, Data Transfer Object or Lazy Loading design patterns in PHP. Below is an explanation about each of these wrapper classes.

Contents:

- [Wrapper](#Wrapper)
- [SetterGetterWrapper](#SetterGetterWrapper)
- [MultipleInstancesWrapper](#MultipleInstancesWrapper)
- [GenericNullObject](#GenericNullObject)
- [GhostWrapper](#GhostWrapper)

Wrapper
-------

[](#wrapper)

The `Wrapper` class is the most basic wrapper implementation providing mechanisms for augmenting the wrapee functionality. We must extend this class for using it on a wrapee (an object that is going to be wrapped).

First of all, we must implement the `getWrapeeClass` method by returning the wrapee class name. That is necessary since the wrapper instantiation checks wether the wrapee is a subtype (or type) of that class:

```
use SimpleWrapper\Wrapper;

class ProductWrapper extends Wrapper
{
    protected function getWrapeeClass()
    {
        return "Product";
    }
}
```

Our wrapper is ready to use, we just need a `Product` instance that is going to be wrapped. Let's suppose our `Product` class is defined as:

```
class Product
{
    protected $id;
    protected $name;
    protected $price;

    public function __construct($id, $name, $price)
    {
        $this->id = $id;
        $this->name = $name;
        $this->price = $price;
    }

    public function getName() {return $this->name;}
    public function getPrice() {return $this->price;}
    public function calculateCost($q) {return $this->price * $q;}
}
```

Then we can access the product's methods from the wrapper instance:

```
$product = new Product(11, "Apple", 2.30);
$productWrapper = new ProductWrapper($product);

echo $productWrapper->getName(); // Apple

echo $productWrapper->calculateCost(10); // 23
```

We can extend the product functionality by re-implementing the product methods on the wrapper:

```
use SimpleWrapper\Wrapper;

class ProductWrapper extends Wrapper
{
    protected function getWrapeeClass()
    {
        return "Product";
    }

    public function calculateCost($q)
    {
        return "The cost is: " . $this->wrapee->calculateCost($q);
    }
}
```

This piece of extra code results in:

```
$product = new ProductWrapper(new Product(11, "Apple", 2.30));

echo $product->getName(); // Apple

echo $product->calculateCost(10); // The cost is: 23
```

Since all the wrapee methods can be invoked from the wrapper class, we can use the wrapper as a wrapee proxy.

SetterGetterWrapper
-------------------

[](#settergetterwrapper)

The `SetterGetterWrapper` is an extension of the `Wrapper` class that can be used to access the setters and getters of the wrapee.

We use it as we did wen using the `Wrapper` class:

```
use SimpleWrapper\SetterGetterWrapper;

class ProductWrapper extends SetterGetterWrapper
{
    protected function getWrapeeClass()
    {
        return "Product";
    }

    public function calculateCost($q)
    {
        return "The cost is: " . $this->wrapee->calculateCost($q);
    }
}

//////////////////////////
$product = new ProductWrapper(new Product(11, "Apple", 2.30));

echo $product->getName(); // Apple

echo $product->calculateCost(10); // The cost is: 23
```

Let's say our `Product` class has some setters like follow:

```
class Product
{
    protected $id;
    protected $name;
    protected $price;

    public function __construct($id, $name, $price)
    {
        $this->id = $id;
        $this->name = $name;
        $this->price = $price;
    }

    public function getName() {return $this->name;}
    public function getPrice() {return $this->price;}
    public function setName($n) {$this->name = $n;}
    public function setPrice($p) {$this->price = $p;}
    public function calculateCost($q) {return $this->price * $q;}
}
```

Then, we could access them from the wrapper by doing `setName()` or `getName`. Instead, the `SetterGetterWrapper` introduces the following feature for accessing the wrapee properties:

```
$product = new ProductWrapper(new Product(11, "Apple", 2.30));

echo $product->name; // Apple

echo $product->calculateCost(10); // The cost is: 23

$product->price = 5.60;

echo $product->price; // 5.60
```

For accessing the property `$product->name`, there must exists a method called `getName` or `getname` defined on any of the wrapper or wrapee class, or the `name` property must be defined as `public` on the wrapee. This also applies wen doing `$product-> = ;`.

MultipleInstancesWrapper
------------------------

[](#multipleinstanceswrapper)

As we can infer, the `MultipleInstancesWrapper` can be used for wrapping/extending the wrapped objects' functionalities. This class can be used as a *DataTransferObject* since allow us to access methods that can be defined on multiple objects.

Let's define the following class:

```
class Person
{
    protected $id;
    protected $name;
    protected $age;

    public function __construct($id, $name, $age)
    {
        $this->id = $id;
        $this->name = $name;
        $this->age = $age;
    }

    public function getName(){return $this->name;}
    public function getAge(){return $this->age;}
    public function isOld(){return $this->age > 60;}
}
```

We can use the `MultipleInstancesWrapper` as is, since it is not an `abstract` class. However, a better practice is extending it so we can provide extra code for augmenting the generic capabilities of the wrapper class:

```
use SimpleWrapper\MultipleInstancesWrapper;

class PPWrapper extends MultipleInstancesWrapper
{
    /**
     * @Override
     */
	protected validateWrapees(array $objects)
    {
        parent::validateWrapees($objects);
        // do extra validation, e.g: validate that the first object is a Person object
    }
}
```

`PPWrapper` stands for "person and product wrapper". We can use it as follows:

```
$wrapper = new PPWrapper(
	new Person(111, 'Peter', 45),
    new Product(222, 'Apple', 5.60)
);

echo $wrapper->calculateCost(100); // 560

echo $wrapper->isOld(); // false
```

What happen if we try to access the `getName` method? That method is defined on both wrapped objects, so we need to specify which class will act as the provider for the method by implementing `getProviderClassForMethod` on the wrapper:

```
use SimpleWrapper\MultipleInstancesWrapper;

class PPWrapper extends MultipleInstancesWrapper
{
    protected function getProviderClassForMethod($method)
    {
        if ($method === 'getName') {
            return 'Product';
        }
    }
}
///////////////////
$wrapper = new PPWrapper(
	new Person(111, 'Peter', 45),
    new Product(222, 'Apple', 5.60)
);

echo $wrapper->calculateCost(100); // 560

echo $wrapper->isOld(); // false

echo $wrapper->getName(); // Apple
```

Without the `getProviderClassForMethod` implementation, the wrapper just invokes the method on the first object that defines it.

GenericNullObject
-----------------

[](#genericnullobject)

The `GenericNullObject` class provides the basics for implementing the *Null Object* design pattern. First, we need to extend the class by defining the `getClassName` method:

```
use SimpleWrapper\GenericNullObject;

class NullProduct extends GenericNullObject
{
    protected function getClassName()
    {
        return "Product";
    }
}
```

Now we are ready to use the null product implementation. By default, all its methods return `null`:

```
$product = new NullProduct();

echo $product->getName(); // null

echo $product->getPrice(); // null
```

We can define our default return type for all the methods overriding the `getDefaultReturnType` method defined on `GenericNullObject`:

```
use SimpleWrapper\GenericNullObject;

class NullProduct extends GenericNullObject
{
    protected function getClassName(){return "Product";}

    protected function getDefaultReturnType(){return false;}
}

/// -------------------
$product = new NullProduct();

echo $product->getName(); // false

echo $product->getPrice(); // false
```

Also, we can be more specific defining the concrete return type for each method name on the `getReturnTypes` method provided by `GenericNullObject`. There we must define an associative array like the following:

```
use SimpleWrapper\GenericNullObject;

class NullProduct extends GenericNullObject
{
    protected function getClassName(){return "Product";}

	protected function getReturnTypes()
    {
        return [
          	'getName' => '',
            'getPrice' => 0
        ];
    }
}

/// -------------------
$product = new NullProduct();

echo $product->getName(); // ''

echo $product->getPrice(); // 0
```

GhostWrapper
------------

[](#ghostwrapper)

The `GhostWrapper` class let us implement the *lazy loading* pattern on objects that can be expensive to load in memory. `GhostWrapper` is an extension of `SetterGetterWrapper`.

Let's define our `Product` class as follows:

```
class Product
{
    protected $id;
    protected $name = null;
    protected $price = null;
    protected $vendors = null;

    public function __construct($id) {$this->id = $id;}

    public function getName() {return $this->name;}
    public function getPrice() {return $this->price;}
    public function fetchVendors() {return $this->vendors;}

    public function loadProductProperties()
    {
        // load properties from a data repository using the id
    }

    public function loadVendors()
    {
        // load vendors from data repository using the id
    }
}
```

The `Product` class is a *Ghost*. It can be in three states at a specific time: completed loaded, partially loaded or not loaded. By using the `GhostWrapper` class we can give some transparency to the product class users that shouldn't be conscious of the loading mechanics.

We must implement various methods for extending the `GhostWrapper` class. The `wrapeeMethodLoaded` must return `true` if the wrapped object can execute the method. If it cannot, then the `loadWrapeeMethod` is called for set the wrapped object able to execute it. This same idea applies when defining the methods `wrapeeGetterLoaded`, `loadWrapeeGetter`. Let's see an example below:

```
use SimpleWrapper\GhostWrapper;

class ProductGhost extends GhostWrapper
{
    protected function getWrapeeClass(){return 'Product';}

    protected function wrapeeMethodLoaded($method, $args)
    {
        if ($method === 'fetchVendors')
            return $this->wrapee->fetchVendors() !== null;
        if ($method === 'getName')
            return $this->wrapeeGetterLoaded('name');
        if ($method === 'getPrice')
            return $this->wrapeeGetterLoaded('price');
        return true;
    }

    protected function loadWrapeeMethod($method, $args)
    {
        if ($method === 'fetchVendors')
            return $this->wrapee->loadVendors();
        return $this->wrapee->loadProductProperties();
    }

    protected function wrapeeGetterLoaded($property)
    {
        return $this->wrapee->{$property} !== null;
    }

    protected function loadWrapeeGetter($property)
    {
        return $this->wrapee->loadProductProperties();
    }
}
```

This basic implementation let us work with a product wrapper without worrying about the loading of the object data. By default, the setters for the object are always loaded (since we can always set a value to an object property), however we can override the methods `wrapeeSetterLoaded` and `loadWrapeeSetter` if needed.

Below we can see the ghost wrapper behavior in action:

```
$product = new ProductGhost(
	new Product(111)
);

echo $product->name; // this line causes the loading of the name and price

print_r($product->fetchVendors()); // this line causes the loading of the vendors
```

The product is instantiated with just the id of the object. The calling on `$product->name` results in invoking `wrapeeGetterLoaded('name')` that returns `false`. Since it is false, the `loadWrapeeGetter('name')` method is invoked. That results in the name and price properties being loaded.

This same logic applies when calling `fetchVendors`. In this case, the loading of the vendors is triggered on the `loadWrapeeMethod` method.

###  Health Score

16

—

LowBetter than 5% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity0

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity34

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/58793996?v=4)[Lucas Pereyra](/maintainers/perlucas)[@perlucas](https://github.com/perlucas)

---

Top Contributors

[![perlucas](https://avatars.githubusercontent.com/u/58793996?v=4)](https://github.com/perlucas "perlucas (6 commits)")

### Embed Badge

![Health badge](/badges/perlucas-phpwrapper/health.svg)

```
[![Health](https://phpackages.com/badges/perlucas-phpwrapper/health.svg)](https://phpackages.com/packages/perlucas-phpwrapper)
```

PHPackages © 2026

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