PHPackages                             webinarium/php-properties - 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. webinarium/php-properties

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

webinarium/php-properties
=========================

Automatic properties implementation for PHP

1.1.0(5y ago)41.7kMITPHPPHP &gt;=7.4CI failing

Since May 28Pushed 5y ago2 watchersCompare

[ Source](https://github.com/webinarium/php-properties)[ Packagist](https://packagist.org/packages/webinarium/php-properties)[ Docs](https://github.com/webinarium/php-properties)[ RSS](/packages/webinarium-php-properties/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (5)Dependencies (2)Versions (6)Used By (0)

[![PHP](https://camo.githubusercontent.com/b43c9d6cd8939c4868f963284928566c4c35dd2da0725c027f95a3d62f2f0329/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d372e342532422d626c75652e737667)](https://secure.php.net/migration74)[![Latest Stable Version](https://camo.githubusercontent.com/b59c6bb024d35f4c0125ce6495fc474718382f2055d0ee08abfeaed363da998f/68747470733a2f2f706f7365722e707567782e6f72672f776562696e617269756d2f7068702d70726f706572746965732f762f737461626c65)](https://packagist.org/packages/webinarium/php-properties)[![Build Status](https://camo.githubusercontent.com/65c00fa3d0a58ce33339ede719df33b8b8778d85fb3793e02f65b99a52d653fb/68747470733a2f2f7472617669732d63692e6f72672f776562696e617269756d2f7068702d70726f706572746965732e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/webinarium/php-properties)[![Code Coverage](https://camo.githubusercontent.com/5597d43cb5ad54b0452884a5b6789707025675530174eb88830ab2f4d28f6d04/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f776562696e617269756d2f7068702d70726f706572746965732f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/webinarium/php-properties/?branch=master)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/d79525b6d5c131ef022561c24964aaa70c1e9e235121a979d9b48f3b6f8d6a2a/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f776562696e617269756d2f7068702d70726f706572746965732f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/webinarium/php-properties/?branch=master)

Automatic properties implementation for PHP
===========================================

[](#automatic-properties-implementation-for-php)

Tl;dr
-----

[](#tldr)

The library provides few helper traits:

- to simulate automatic/custom properties as they are defined in C#,
- to simulate object initialization on creation as it works in C#.

Installation
------------

[](#installation)

The recommended way to install is via Composer:

```
composer require webinarium/php-properties
```

The Problem
-----------

[](#the-problem)

Let's assume we need a class to represent a user's entity (quite popular case in the webdev world). The class must provide read-only ID, writeable first and last names, and a helper function to get the full name compound from the first and last ones:

```
class User
{
    protected int $id;
    protected string $firstName;
    protected string $lastName;

    public function getId(): int
    {
        return $this->id;
    }

    public function getFirstName(): string
    {
        return $this->firstName;
    }

    public function setFirstName(string $firstName)
    {
        $this->firstName = $firstName;
    }

    public function getLastName(): string
    {
        return $this->lastName;
    }

    public function setLastName(string $lastName)
    {
        $this->lastName = $lastName;
    }

    public function getFullName(): string
    {
        return $this->firstName . ' ' . $this->lastName;
    }
}
```

Only three properties and one extra function to get the full name, but our class is already bloated with a lot of getters and setters.

Meanwhile in C# the same class could be implemented as following:

```
public class User
{
    public int Id { get; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName {
        get {
            return FirstName + " " + LastName;
        }
    }
}
```

Nice and easy - even if you don't know C# you still understand what this code says. How can we get the same in PHP?

Magic methods
-------------

[](#magic-methods)

Of course, the first thought is magic methods, so we can rewrite the class as following:

```
/**
 * @property-read int    $id
 * @property      string $firstName
 * @property      string $lastName
 * @property-read string $fullName
 */
class User
{
    protected int $id;
    protected string $firstName;
    protected string $lastName;

    public function __isset($name)
    {
        if ($name === 'fullName') {
            return true;
        }

        return property_exists($this, $name);
    }

    public function __get($name)
    {
        if ($name === 'fullName') {
            return $this->firstName . ' ' . $this->lastName;
        }

        return property_exists($this, $name)
            ? $this->$name
            : null;
    }

    public function __set($name, $value)
    {
        if ($name === 'id') {
            return;
        }

        if (property_exists($this, $name)) {
            $this->$name = $value;
        }
    }
}
```

Well, it works, but it takes nearly the same amount of code as the original class. Assume more properties, where some are read-only as `Id` and some a "virtual" as `fullName` and you will end up with long `switch` operators in all three magic functions. Also, I bet your IDE doesn't autocomplete these properties, so we have to append the class with `@property` annotations.

Annotations
-----------

[](#annotations)

We can't change the PHP syntax, but we still can extend it using annotations. Really, if we had to write the annotations in the above example, why not reuse them instead of update all three magic functions each time we introduce a new property. And this is exactly what this library does, providing required functionality in the `PropertyTrait`.

If you include the `PropertyTrait` in your class, the `@property` annotations become a required declaration regarding your properties. Let's refactor our class using the trait:

```
/**
 * @property-read  int    $id
 * @property       string $firstName
 * @property       string $lastName
 * @property-read  string $fullName
 */
class User
{
    use PropertyTrait;

    protected int $id;
    protected string $firstName;
    protected string $lastName;

    protected function getters(): array
    {
        return [
            'fullName' => fn (): string => $this->firstName . ' ' . $this->lastName,
        ];
    }
}
```

Maybe still not as elegant as the C# version, but much closer, isn't it?

Automatic properties
--------------------

[](#automatic-properties)

Using `@property` annotation you can expose any existing protected or private property. To make a property read-only (or write-only) use a `@property-read` (or `@property-write`) annotation instead. If you don't specify a `@property` annotation for some existing non-public property, it will remain hidden.

Custom (virtual) properties
---------------------------

[](#custom-virtual-properties)

The trait contains two protected functions - `getters` and `setters` - which can be overridden in your class. Both functions return associated array of anonymous functions, and keys of the array are names of your virtual properties.

Let's assume we want to store some user-specific settings like user's language and user's timezone. We might have a lot of such configuration options and we don't want to bloat the related database table with the same amount of columns, while all these settings can be stored in a single `settings` array:

```
/**
 * ...
 * @property string $language
 * @property string $timezone
 */
class User
{
    use PropertyTrait;

    ...
    protected array $settings;

    protected function getters(): array
    {
        return [
            'language' => fn (): string => $this->settings['language'] ?? 'en',
            'timezone' => fn (): string => $this->settings['timezone'] ?? 'UTC',
        ];
    }

    protected function setters(): array
    {
        return [

            'language' => function (string $value): void {
                $this->settings['language'] = $value;
            },

            'timezone' => function (string $value): void {
                $this->settings['timezone'] = $value;
            },
        ];
    }
}
```

Actually, you can provide your custom getters and setters via the `getters`/`setters` functions for existing property, too. In this case you will override the default behaviour of the property.

Performance
-----------

[](#performance)

Annotations are expensive. To work around this the trait caches parsed annotations in memory, so they are parsed only once (per web-request). Below is a table of few benchmarks for different ways to work with class properties. Each number is amount of seconds which took to read a property 100000 (one hundred thousand) times. Numbers are calculated from 5 sequental runs.

Method to read a propertyMin timeAvg timeMax timeDirect access to public property0.0070.0080.009Classic getter0.0650.0660.067Magic `__get` function0.0730.0740.075Using `PropertyTrait`0.1730.1750.177Object initialization on creation
---------------------------------

[](#object-initialization-on-creation)

Another nice C# feature lets you initialize object properties when you're creating the object. Taking the same `User` class from above you can create and setup new object in a classic way:

```
var user = new User();

user.FirstName = "Artem";
user.LastName  = "Rodygin";
```

or initialize the properties on creation:

```
var user = new User
{
    FirstName = "Artem",
    LastName  = "Rodygin"
};
```

The library provides another trait - `DataTransferObjectTrait` - to simulate such initialization. Assume we used this trait in our `User` PHP class, then new object can be created as following:

```
$user = new User([
    'firstName' => 'Artem',
    'lastName'  => 'Rodygin',
]);
```

The trait defines a default constructor which takes a single `array` argument. This is an associated array, where keys are names of the properties to initialize. If a property is not found for some of the keys, it will be just skipped.

Development
-----------

[](#development)

```
./bin/php-cs-fixer fix
./bin/phpunit --coverage-text
```

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity67

Established project with proven stability

 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 ~289 days

Total

5

Last Release

2115d ago

Major Versions

0.0.1 → 1.0.02017-08-28

PHP version history (2 changes)0.0.1PHP &gt;=7.0

1.1.0PHP &gt;=7.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/e875e09c96006b56b5aa9d3b9d33c6da38a77ea8df59d24667a852a5fd1102f9?d=identicon)[webinarium](/maintainers/webinarium)

---

Top Contributors

[![webinarium](https://avatars.githubusercontent.com/u/741349?v=4)](https://github.com/webinarium "webinarium (12 commits)")

---

Tags

annotationsphppropertiesannotationsproperties

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/webinarium-php-properties/health.svg)

```
[![Health](https://phpackages.com/badges/webinarium-php-properties/health.svg)](https://phpackages.com/packages/webinarium-php-properties)
```

###  Alternatives

[minime/annotations

The KISS PHP annotations library

229378.6k37](/packages/minime-annotations)[spiral/attributes

PHP attributes reader

233.6M45](/packages/spiral-attributes)[mediawiki/semantic-extra-special-properties

Provides extra special properties for Semantic MediaWiki

3074.6k1](/packages/mediawiki-semantic-extra-special-properties)[marcin-orlowski/lombok-php

Never write boilerplate code for your data class again!

3118.6k1](/packages/marcin-orlowski-lombok-php)[vanilo/properties

Vanilo Properties (Attributes) Module

11105.2k2](/packages/vanilo-properties)[proai/lumen-annotations

Route and event binding annotations for Laravel Lumen

1012.4k](/packages/proai-lumen-annotations)

PHPackages © 2026

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