does this model-pattern have a name?

A few years back, I wrote this answer to a question from which the following idea emerged.

I call these “Type Descriptors”, as I have never been able to find this pattern documented or formally described anywhere – not to be confused with type descriptors in C#, but it’s the most accurate name I’ve been able to come up with, so bear with me.

Here’s my first attempt at a “formal” description:

A Type Descriptor is a type that provides meta-information about
another type.

This pattern can be seen as an alternative to run-time reflection and
annotations, and as such is equally applicable to languages that do or
do not support reflection or annotations.

Type Descriptors are particularly useful as a means of describing
aspects of model types found in for example domain and view-models, as
well as in specialized types of models, such as form-models in a
business- or web-application. Often such applications have many common
aspects, such as the need to label inputs and perform common
validations for e.g. required input, data types and formats, etc. –
the information required by helper objects (or services) to handle
these aspects fits comfortably in descriptors.

A descriptor mirrors the shape of the type it describes – for example,
if a model type User has properties like id, name and email, it’s type
descriptor must have properties id, name and email, but where the
properties on the model type have various value types (in this case
for example integer and string) the properties of the descriptor are
objects that provide information about those properties.

Maintaining identical model type and descriptor shapes may seem like
duplication, in terms of property-names being identical in the model
type and type descriptor – however, this does not violate the DRY
principle as such, since the model type and descriptor, strictly
speaking, are two different types that only happen to have the same
shape, but do not have any overlapping concerns or duplication of any
code; only the property names are duplicates.

I program mostly in PHP on a daily basis, and have used this pattern successfully to build applications. The following example is in PHP, though this could be implemented in any language capable of resolving properties by name at run-time.

A tiny bit of framework is required to implement this, so here goes…

A model-type implementing the following interface can provide a “type descriptor” – a type that describes the model-type itself:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>interface TypeInfo
{
function getType();
}
</code>
<code>interface TypeInfo { function getType(); } </code>
interface TypeInfo
{
    function getType();
}

Individual model-properties are described by “property descriptors” in the “type descriptor”, for which I use a base class along the lines of this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>abstract class PropertyInfo
{
/** @var string */
public $name;
/** @var string */
public $label;
public function __construct($name)
{
$this->name = $name;
}
}
</code>
<code>abstract class PropertyInfo { /** @var string */ public $name; /** @var string */ public $label; public function __construct($name) { $this->name = $name; } } </code>
abstract class PropertyInfo
{
    /** @var string */
    public $name;

    /** @var string */
    public $label;

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

From this class, I derive “property descriptors” for specific types of properties – for example, this type describes a string property:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class StringInfo extends PropertyInfo
{
/**
* @var int|null
*/
public $max_length;
}
</code>
<code>class StringInfo extends PropertyInfo { /** * @var int|null */ public $max_length; } </code>
class StringInfo extends PropertyInfo
{
    /**
     * @var int|null
     */
    public $max_length;
}

Now here’s a sample User model, and it’s “type descriptor” UserType:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class User implements TypeInfo
{
/** @var string */
public $name;
/** @var string */
public $email;
/** @return UserType */
public function getType()
{
return UserType::instance();
}
}
class UserType
{
/** @var StringInfo */
public $name;
/** @var StringInfo */
public $email;
public function __construct()
{
$this->name = new StringInfo('name');
$this->name->label = 'Full Name';
$this->name->max_length = 50;
$this->email = new StringInfo('email');
$this->email->label = 'E-mail Address';
$this->email->max_length = 128;
}
/** @return self */
public static function instance()
{
static $instance;
return $instance ?: $instance = new static();
}
}
</code>
<code>class User implements TypeInfo { /** @var string */ public $name; /** @var string */ public $email; /** @return UserType */ public function getType() { return UserType::instance(); } } class UserType { /** @var StringInfo */ public $name; /** @var StringInfo */ public $email; public function __construct() { $this->name = new StringInfo('name'); $this->name->label = 'Full Name'; $this->name->max_length = 50; $this->email = new StringInfo('email'); $this->email->label = 'E-mail Address'; $this->email->max_length = 128; } /** @return self */ public static function instance() { static $instance; return $instance ?: $instance = new static(); } } </code>
class User implements TypeInfo
{
    /** @var string */
    public $name;

    /** @var string */
    public $email;

    /** @return UserType */
    public function getType()
    {
        return UserType::instance();
    }
}

class UserType
{
    /** @var StringInfo */
    public $name;

    /** @var StringInfo */
    public $email;

    public function __construct()
    {
        $this->name = new StringInfo('name');
        $this->name->label = 'Full Name';
        $this->name->max_length = 50;

        $this->email = new StringInfo('email');
        $this->email->label = 'E-mail Address';
        $this->email->max_length = 128;
    }

    /** @return self */
    public static function instance()
    {
        static $instance;

        return $instance ?: $instance = new static();
    }
}

As you can see, it’s now possible to get the type descriptor either from a User instance by e.g. $user->getType() – notice that the property-names of the “property descriptors” in the “type descriptor” match the property-names in the actual model; using this pattern, it’s my own responsibility to make sure the model and it’s descriptor have the same shape.

Now I can write services and helpers etc. which may consume information from a “type descriptor” while working with model objects – for example, here’s a very simple form helper:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class FormHelper
{
/** @var TypeInfo */
public $model;
/** @var string */
public $prefix;
/**
* @param TypeInfo $model
* @param string $prefix
*/
public function __construct(TypeInfo $model, $prefix)
{
$this->model = $model;
$this->prefix = $prefix;
}
/**
* @param StringInfo $prop
*
* @return string
*/
public function text(StringInfo $prop)
{
$name = $prop->name;
return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>'
. '<input type="text" name="' . $this->prefix . '[' . $name . ']"'
. ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '')
. ' value="' . $this->model->$name . '" id="' . $name . '" />';
}
}
</code>
<code>class FormHelper { /** @var TypeInfo */ public $model; /** @var string */ public $prefix; /** * @param TypeInfo $model * @param string $prefix */ public function __construct(TypeInfo $model, $prefix) { $this->model = $model; $this->prefix = $prefix; } /** * @param StringInfo $prop * * @return string */ public function text(StringInfo $prop) { $name = $prop->name; return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>' . '<input type="text" name="' . $this->prefix . '[' . $name . ']"' . ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '') . ' value="' . $this->model->$name . '" id="' . $name . '" />'; } } </code>
class FormHelper
{
    /** @var TypeInfo */
    public $model;

    /** @var string */
    public $prefix;

    /**
     * @param TypeInfo $model
     * @param string     $prefix
     */
    public function __construct(TypeInfo $model, $prefix)
    {
        $this->model = $model;
        $this->prefix = $prefix;
    }

    /**
     * @param StringInfo $prop
     *
     * @return string
     */
    public function text(StringInfo $prop)
    {
        $name = $prop->name;

        return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>'
            . '<input type="text" name="' . $this->prefix . '[' . $name . ']"'
            . ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '')
            . ' value="' . $this->model->$name . '" id="' . $name . '" />';
    }
}

You would use the form helper like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>$user = new User;
$user->name = 'Rasmus';
$user->email = '[email protected]';
$form = new FormHelper($user, 'user');
$t = $user->getType();
echo $form->text($t->name) . "n";
echo $form->text($t->email) . "n";
</code>
<code>$user = new User; $user->name = 'Rasmus'; $user->email = '[email protected]'; $form = new FormHelper($user, 'user'); $t = $user->getType(); echo $form->text($t->name) . "n"; echo $form->text($t->email) . "n"; </code>
$user = new User;
$user->name = 'Rasmus';
$user->email = '[email protected]';

$form = new FormHelper($user, 'user');

$t = $user->getType();

echo $form->text($t->name) . "n";
echo $form->text($t->email) . "n";

Which would output something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" />
<label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" />
</code>
<code><label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" /> <label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" /> </code>
<label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" />
<label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" />

The two key reasons I enjoy working like this are (1) patterns like rendering forms, mapping post-data to model objects, mapping model-objects to database records, performing input validation and so forth can all be performed by formal helpers and service objects, all of which consume the same single source of information, and (2) everything is “statically typed”, meaning only a single unchecked property-reference (by name, as a string) is made and encapsulated inside the “type descriptor”, and type-hints and inference in a modern IDE (PhpStorm) can provide automated code inspections at development-time, I can safely use automated refactorings, and so forth.

Okay, a rather lengthy discourse, for what boils down to one question: does this pattern have a name? 🙂

Side question: does this constitute (reflective) meta-programming? (The use of this pattern is very similar to e.g. using reflection to obtain annotations from a model, though I find this to be much safer, less complicated, more flexible and transparent.)

9

That is an OOP Data Descriptor. Although you are describing additional information about a class rather than information about bits in memory, the fundamental parity still applies; you’re describing in one place useful aspects about data in another place.

I’d advise you to adopt that name, write up a clearer definition of the pattern, and use the name in code. (“Type” already means something in PHP, so you really shouldn’t use it.) So, your user class could be changed as follows:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class User {
...
public function getDescriptor() {
}
}
class UserDescriptor {
...
}
</code>
<code>class User { ... public function getDescriptor() { } } class UserDescriptor { ... } </code>
class User {
   ...
   public function getDescriptor() {
   }
}

class UserDescriptor {
   ...
}

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

does this model-pattern have a name?

A few years back, I wrote this answer to a question from which the following idea emerged.

I call these “Type Descriptors”, as I have never been able to find this pattern documented or formally described anywhere – not to be confused with type descriptors in C#, but it’s the most accurate name I’ve been able to come up with, so bear with me.

Here’s my first attempt at a “formal” description:

A Type Descriptor is a type that provides meta-information about
another type.

This pattern can be seen as an alternative to run-time reflection and
annotations, and as such is equally applicable to languages that do or
do not support reflection or annotations.

Type Descriptors are particularly useful as a means of describing
aspects of model types found in for example domain and view-models, as
well as in specialized types of models, such as form-models in a
business- or web-application. Often such applications have many common
aspects, such as the need to label inputs and perform common
validations for e.g. required input, data types and formats, etc. –
the information required by helper objects (or services) to handle
these aspects fits comfortably in descriptors.

A descriptor mirrors the shape of the type it describes – for example,
if a model type User has properties like id, name and email, it’s type
descriptor must have properties id, name and email, but where the
properties on the model type have various value types (in this case
for example integer and string) the properties of the descriptor are
objects that provide information about those properties.

Maintaining identical model type and descriptor shapes may seem like
duplication, in terms of property-names being identical in the model
type and type descriptor – however, this does not violate the DRY
principle as such, since the model type and descriptor, strictly
speaking, are two different types that only happen to have the same
shape, but do not have any overlapping concerns or duplication of any
code; only the property names are duplicates.

I program mostly in PHP on a daily basis, and have used this pattern successfully to build applications. The following example is in PHP, though this could be implemented in any language capable of resolving properties by name at run-time.

A tiny bit of framework is required to implement this, so here goes…

A model-type implementing the following interface can provide a “type descriptor” – a type that describes the model-type itself:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>interface TypeInfo
{
function getType();
}
</code>
<code>interface TypeInfo { function getType(); } </code>
interface TypeInfo
{
    function getType();
}

Individual model-properties are described by “property descriptors” in the “type descriptor”, for which I use a base class along the lines of this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>abstract class PropertyInfo
{
/** @var string */
public $name;
/** @var string */
public $label;
public function __construct($name)
{
$this->name = $name;
}
}
</code>
<code>abstract class PropertyInfo { /** @var string */ public $name; /** @var string */ public $label; public function __construct($name) { $this->name = $name; } } </code>
abstract class PropertyInfo
{
    /** @var string */
    public $name;

    /** @var string */
    public $label;

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

From this class, I derive “property descriptors” for specific types of properties – for example, this type describes a string property:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class StringInfo extends PropertyInfo
{
/**
* @var int|null
*/
public $max_length;
}
</code>
<code>class StringInfo extends PropertyInfo { /** * @var int|null */ public $max_length; } </code>
class StringInfo extends PropertyInfo
{
    /**
     * @var int|null
     */
    public $max_length;
}

Now here’s a sample User model, and it’s “type descriptor” UserType:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class User implements TypeInfo
{
/** @var string */
public $name;
/** @var string */
public $email;
/** @return UserType */
public function getType()
{
return UserType::instance();
}
}
class UserType
{
/** @var StringInfo */
public $name;
/** @var StringInfo */
public $email;
public function __construct()
{
$this->name = new StringInfo('name');
$this->name->label = 'Full Name';
$this->name->max_length = 50;
$this->email = new StringInfo('email');
$this->email->label = 'E-mail Address';
$this->email->max_length = 128;
}
/** @return self */
public static function instance()
{
static $instance;
return $instance ?: $instance = new static();
}
}
</code>
<code>class User implements TypeInfo { /** @var string */ public $name; /** @var string */ public $email; /** @return UserType */ public function getType() { return UserType::instance(); } } class UserType { /** @var StringInfo */ public $name; /** @var StringInfo */ public $email; public function __construct() { $this->name = new StringInfo('name'); $this->name->label = 'Full Name'; $this->name->max_length = 50; $this->email = new StringInfo('email'); $this->email->label = 'E-mail Address'; $this->email->max_length = 128; } /** @return self */ public static function instance() { static $instance; return $instance ?: $instance = new static(); } } </code>
class User implements TypeInfo
{
    /** @var string */
    public $name;

    /** @var string */
    public $email;

    /** @return UserType */
    public function getType()
    {
        return UserType::instance();
    }
}

class UserType
{
    /** @var StringInfo */
    public $name;

    /** @var StringInfo */
    public $email;

    public function __construct()
    {
        $this->name = new StringInfo('name');
        $this->name->label = 'Full Name';
        $this->name->max_length = 50;

        $this->email = new StringInfo('email');
        $this->email->label = 'E-mail Address';
        $this->email->max_length = 128;
    }

    /** @return self */
    public static function instance()
    {
        static $instance;

        return $instance ?: $instance = new static();
    }
}

As you can see, it’s now possible to get the type descriptor either from a User instance by e.g. $user->getType() – notice that the property-names of the “property descriptors” in the “type descriptor” match the property-names in the actual model; using this pattern, it’s my own responsibility to make sure the model and it’s descriptor have the same shape.

Now I can write services and helpers etc. which may consume information from a “type descriptor” while working with model objects – for example, here’s a very simple form helper:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class FormHelper
{
/** @var TypeInfo */
public $model;
/** @var string */
public $prefix;
/**
* @param TypeInfo $model
* @param string $prefix
*/
public function __construct(TypeInfo $model, $prefix)
{
$this->model = $model;
$this->prefix = $prefix;
}
/**
* @param StringInfo $prop
*
* @return string
*/
public function text(StringInfo $prop)
{
$name = $prop->name;
return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>'
. '<input type="text" name="' . $this->prefix . '[' . $name . ']"'
. ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '')
. ' value="' . $this->model->$name . '" id="' . $name . '" />';
}
}
</code>
<code>class FormHelper { /** @var TypeInfo */ public $model; /** @var string */ public $prefix; /** * @param TypeInfo $model * @param string $prefix */ public function __construct(TypeInfo $model, $prefix) { $this->model = $model; $this->prefix = $prefix; } /** * @param StringInfo $prop * * @return string */ public function text(StringInfo $prop) { $name = $prop->name; return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>' . '<input type="text" name="' . $this->prefix . '[' . $name . ']"' . ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '') . ' value="' . $this->model->$name . '" id="' . $name . '" />'; } } </code>
class FormHelper
{
    /** @var TypeInfo */
    public $model;

    /** @var string */
    public $prefix;

    /**
     * @param TypeInfo $model
     * @param string     $prefix
     */
    public function __construct(TypeInfo $model, $prefix)
    {
        $this->model = $model;
        $this->prefix = $prefix;
    }

    /**
     * @param StringInfo $prop
     *
     * @return string
     */
    public function text(StringInfo $prop)
    {
        $name = $prop->name;

        return '<label for="' . $name . '">' . htmlspecialchars($prop->label) . '</label>'
            . '<input type="text" name="' . $this->prefix . '[' . $name . ']"'
            . ($prop->max_length ? ' maxlength="' . $prop->max_length . '"' : '')
            . ' value="' . $this->model->$name . '" id="' . $name . '" />';
    }
}

You would use the form helper like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>$user = new User;
$user->name = 'Rasmus';
$user->email = '[email protected]';
$form = new FormHelper($user, 'user');
$t = $user->getType();
echo $form->text($t->name) . "n";
echo $form->text($t->email) . "n";
</code>
<code>$user = new User; $user->name = 'Rasmus'; $user->email = '[email protected]'; $form = new FormHelper($user, 'user'); $t = $user->getType(); echo $form->text($t->name) . "n"; echo $form->text($t->email) . "n"; </code>
$user = new User;
$user->name = 'Rasmus';
$user->email = '[email protected]';

$form = new FormHelper($user, 'user');

$t = $user->getType();

echo $form->text($t->name) . "n";
echo $form->text($t->email) . "n";

Which would output something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code><label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" />
<label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" />
</code>
<code><label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" /> <label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" /> </code>
<label for="name">Full Name</label><input type="text" name="user[name]" maxlength="50" value="Rasmus" id="name" />
<label for="email">E-mail Address</label><input type="text" name="user[email]" maxlength="128" value="[email protected]" id="email" />

The two key reasons I enjoy working like this are (1) patterns like rendering forms, mapping post-data to model objects, mapping model-objects to database records, performing input validation and so forth can all be performed by formal helpers and service objects, all of which consume the same single source of information, and (2) everything is “statically typed”, meaning only a single unchecked property-reference (by name, as a string) is made and encapsulated inside the “type descriptor”, and type-hints and inference in a modern IDE (PhpStorm) can provide automated code inspections at development-time, I can safely use automated refactorings, and so forth.

Okay, a rather lengthy discourse, for what boils down to one question: does this pattern have a name? 🙂

Side question: does this constitute (reflective) meta-programming? (The use of this pattern is very similar to e.g. using reflection to obtain annotations from a model, though I find this to be much safer, less complicated, more flexible and transparent.)

9

That is an OOP Data Descriptor. Although you are describing additional information about a class rather than information about bits in memory, the fundamental parity still applies; you’re describing in one place useful aspects about data in another place.

I’d advise you to adopt that name, write up a clearer definition of the pattern, and use the name in code. (“Type” already means something in PHP, so you really shouldn’t use it.) So, your user class could be changed as follows:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class User {
...
public function getDescriptor() {
}
}
class UserDescriptor {
...
}
</code>
<code>class User { ... public function getDescriptor() { } } class UserDescriptor { ... } </code>
class User {
   ...
   public function getDescriptor() {
   }
}

class UserDescriptor {
   ...
}

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật