{"id":6693,"date":"2018-04-11T09:10:19","date_gmt":"2018-04-11T07:10:19","guid":{"rendered":"https:\/\/anexia.com\/stagingblog\/?p=6693"},"modified":"2022-04-21T13:40:22","modified_gmt":"2022-04-21T11:40:22","slug":"reflection-in-php-projects","status":"publish","type":"post","link":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/","title":{"rendered":"Reflection in PHP projects"},"content":{"rendered":"<p>The term \u201creflection\u201d in <a href=\"https:\/\/anexia.com\/en\/software-development\/\">software development<\/a> means that a program knows its own structure at runtime and can also modify it. This capability is also referred to as \u201cintrospection\u201d. In the PHP area, reflection is used to ensure type safety in the program code. As web developer at Anexia I know PHP like the back of my hand and I just use reflection quite often. Below I will explain how it works in practical terms, and why it is a very useful tool.<\/p>\n<h2>Type safety in PHP<\/h2>\n<p><a href=\"https:\/\/anexia.com\/en\/software-development\/web-development\/php-development\/\">PHP<\/a> is not exactly known for being a typed language. It is debatable whether this should be considered as positive or negative &#8211; both sides have their arguments.<\/p>\n<p>In principle, PHP has four different basic data types: scalar, array, object and resource. The scalar data types include, among others:  Boolean, integer, double, and string. Object classes, on the other hand, are complex data structures that are individually composed of the types listed above.<\/p>\n<h2>Effect of weak typing<\/h2>\n<p>Unlike strongly typed languages, such as Java or C, the types of data in the memory can change dynamically in PHP. For example, there is always an attempt to determine an integer value for scalar types. Variables also do not have to be declared explicitly in PHP. This means that the declaration of a new variable does not necessarily have to specify a data type in this case.<\/p>\n<p>On the one hand, this gives you the advantage of being flexible in the use of these variables, since you can always dynamically modify their use with respect to the data type without causing compiler problems. What may sound very appealing to many, however, also has a decisive disadvantage: perhaps the developer makes a small error, and he suddenly begins to reinitialize an array as an object in the middle of the program code. It could work fine for the rest of the process &#8211; but what about the remaining code that is based on the original array?<\/p>\n<p>To demonstrate the behavior of PHP, let us consider the following example:<\/p>\n<pre class=\"lang:php decode:true \">$foo = \"image\";\r\n\r\n$foo == \"image\"\t\t\/\/ true\r\n$foo == 1\t\t\t\/\/ false\r\n$foo == 0\t\t\t\/\/ true\r\n$foo === 0 \t\t\t\/\/ false<\/pre>\n<p>As you can see, the \u201cimage\u201d string corresponds to the numeric value &#8222;0&#8220;. This is because PHP first tries to convert the string to an integer, which also works fine in this case. If you transferred this string to the <strong>intval()<\/strong> function, you would actually obtain the value &#8222;0&#8220; &#8211; and a comparison of &#8222;0&#8220; and &#8222;0&#8220; is &#8222;true\u201d after all.<\/p>\n<p>This can be avoided, for example, by stricter type-safe operators, such as &#8222;===&#8220; and &#8222;! ==&#8220;.<\/p>\n<h2>The reflection API in PHP<\/h2>\n<p>If you work a lot with frameworks, you can immediately confirm that they make heavy use of annotations or enums. Although you can initially simply accept this fact, when you consider that PHP does not actually support these language constructs at all, the following question quickly poses itself: What are they actually good for? In the following example, we want to demonstrate the purpose of such constructs and point out the magic of it all.<\/p>\n<h3>An example<\/h3>\n<p>Let\u2019s prepare a simple example class:<\/p>\n<pre class=\"lang:php decode:true \">class Example {\r\n\r\n\tprivate $attribute1;\r\n\r\n\tprotected $attribute2;\r\n\r\n\tpublic $attribute3;\r\n\r\n\tconst PI = 3.1415;\r\n\r\n\tpublic function __construct() {\r\n\t\t$this-&gt;attribute1 = \"Lorem ipsum\";\r\n\t\t$this-&gt;attribute2 = 36;\r\n\t\t$this-&gt;attribute3 = 2 * self::PI;\r\n\t}\r\n\r\n\r\n\tpublic function getAttribute1() {\r\n\t\treturn $this-&gt;attribute1;\r\n\t}\r\n\t\r\n\tpublic function setAttribute1($attribute1) {\r\n\t\t$this-&gt;attribute1 = $attribute1;\r\n\t}\r\n\r\n\tprivate function getAttribute2() {\r\n\t\treturn $this-&gt;attribute2;\r\n\t}\r\n\t\r\n}<\/pre>\n<p>As you can see, this example class provides some simple methods and attributes. We will use it as a simple starting point in the next examples.<\/p>\n<h4>Outputting object dump<\/h4>\n<p>The reflection API makes it possible to analyze the properties of this class from the outside. To obtain a full export, <strong>reflection()<\/strong> provides the static <strong>export()<\/strong> method.<\/p>\n<pre class=\"lang:php decode:true \">$reflection_object = new ReflectionClass( Example::class );\r\n\r\nReflection::export( $reflection_object );<\/pre>\n<p>The export of our example class would then look as follows:<\/p>\n<pre class=\"lang:php decode:true\">Class [ &lt;user&gt; class Example ] {\r\n  @@ [...][...] 2-30\r\n\r\n  - Constants [1] {\r\n    Constant [ float PI ] { 3.1415 }\r\n  }\r\n\r\n  - Static properties [0] {\r\n  }\r\n\r\n  - Static methods [0] {\r\n  }\r\n\r\n  - Properties [3] {\r\n    Property [ &lt;default&gt; private $attribute1 ]\r\n    Property [ &lt;default&gt; protected $attribute2 ]\r\n    Property [ &lt;default&gt; public $attribute3 ]\r\n  }\r\n\r\n  - Methods [4] {\r\n    Method [ &lt;user, ctor&gt; public method __construct ] {\r\n      @@ [...][...] 12 - 16\r\n    }\r\n\r\n    Method [ &lt;user&gt; public method getAttribute1 ] {\r\n      @@ [...][...] 19 - 21\r\n    }\r\n\r\n    Method [ &lt;user&gt; public method setAttribute1 ] {\r\n      @@ [...][...] 23 - 25\r\n\r\n      - Parameters [1] {\r\n        Parameter #0 [ &lt;required&gt; $attribute1 ]\r\n      }\r\n    }\r\n\r\n    Method [ &lt;user&gt; private method getAttribute2 ] {\r\n      @@ [...][...] 27 - 29\r\n    }\r\n  }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h4>Reading out methods<\/h4>\n<p>If you for example want to know which methods are provided in the \u201cExample\u201d class, you can output this relatively easily using the following construct:<\/p>\n<pre class=\"lang:php decode:true \">$reflection_class = new ReflectionClass(\"Example\");\r\n\r\nforeach ($reflection_class-&gt;getMethods() as $method) {\r\n\techo $method-&gt;getName() . \"\\n\";\r\n}<\/pre>\n<p>As a result, you get the following:<\/p>\n<ul>\n<li>__construct<\/li>\n<li>getAttribute1<\/li>\n<li>setAttribute1<\/li>\n<li>getAttribute2<\/li>\n<\/ul>\n<p>As a parameter, <strong>ReflectionClass()<\/strong> expects only the full class name (including the namespace, if any) of the class being analyzed. To make initialization look even better, you can also directly use PHP\u2019s class name resolution\u2014<\/p>\n<pre class=\"lang:php decode:true \">$reflection_class = new ReflectionClass( Example::class );<\/pre>\n<p>this is especially useful if you are working a lot with namespaces.<\/p>\n<p>In addition to the method names, however, other information can also be read out:<\/p>\n<pre class=\"lang:php decode:true \">$reflection_class = new ReflectionClass( Example::class );\r\n\r\nforeach ($reflection_class-&gt;getMethods() as $method) {\r\n\techo $method-&gt;getName() . \"\\n\";\r\n\t\r\n\techo \"Number of parameters: \" . $method-&gt;getNumberOfParameters() . \"\\n\";\r\n\techo \"Is private: \" . ($method-&gt;isPrivate() ? 'Yes' : 'No') . \"\\n\\n\";\r\n}<\/pre>\n<p>As a result, you get the following:<\/p>\n<ul>\n<li>__construct<br \/>\nNumber of parameters: 0<br \/>\nIs private: No<\/li>\n<li>getAttribute1<br \/>\nNumber of parameters: 0<br \/>\nIs private: No<\/li>\n<li>setAttribute1<br \/>\nNumber of parameters: 1<br \/>\nIs private: No<\/li>\n<li>getAttribute2<br \/>\nNumber of parameters: 0<br \/>\nIs private: Yes<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h4>Reading out attributes<\/h4>\n<p>The same behavior can incidentally also be applied to attributes. Instead of <strong>using getMethods()<\/strong> you simply use <strong>getProperties()<\/strong>.<\/p>\n<pre class=\"lang:php decode:true \">$reflection_class = new ReflectionClass(Example::class);\r\n\r\nforeach ($reflection_class-&gt;getProperties() as $property) {\r\n    echo $property-&gt;getName() . \"\\n\";\r\n    \r\n    echo \"Is private: \" . ($property-&gt;isPrivate() ? 'Yes' : 'No') . \"\\n\\n\";\r\n}<\/pre>\n<p>The result is comparable to that of the previous methods:<\/p>\n<ul>\n<li>attribute1<br \/>\nIs private: Yes<\/li>\n<li>attribute2<br \/>\nIs private: No<\/li>\n<li>attribute3<br \/>\nIs private: No<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h4>Executing methods using reflection<\/h4>\n<p>The reflection API incidentally also has a special feature. It can be used to execute private methods, something that would not be possible in the normal program context.<\/p>\n<pre class=\"lang:php decode:true \">$object = new Example();\r\n\r\n$reflection_object = new ReflectionObject($object);\r\n$method = $reflection_object-&gt;getMethod(\"getAttribute1\");\r\n\r\ntry {\r\n\techo $method-&gt;invoke($object);\r\n\t\r\n} catch (ReflectionException $e) {\r\n\techo \"Forbidden!\";\r\n}<\/pre>\n<p>You now get the string \u201cLorem ipsum\u201d as an output. This is because the activated method <strong>getAttribute1()<\/strong> returns the <strong>attribute1<\/strong> attribute, which was initialized in the constructor of the class with this string. As you can see, activating this method worked wonderfully.<\/p>\n<p>In the next step, we will now try to activate our private method <strong>getAttribute2()<\/strong> by entering the desired method name in <strong>getMethod()<\/strong>:<\/p>\n<pre class=\"lang:php decode:true \">$object = new Example();\r\n\r\n$reflection_object = new ReflectionObject($object);\r\n$method = $reflection_object-&gt;getMethod(\"getAttribute2\");\r\n\r\ntry {\r\n\techo $method-&gt;invoke($object);\r\n\t\r\n} catch (ReflectionException $e) {\r\n\techo \"Forbidden!\";\r\n}<\/pre>\n<p>We now get \u201cForbidden!\u201d as an output, as defined in our exception handling. As expected, this is because you cannot directly access private methods outside the instantiated class.<\/p>\n<p>However, this is precisely where the reflection API provides a useful tool with <strong>setAccessible()<\/strong>.<\/p>\n<pre class=\"lang:php decode:true \">$object = new Example();\r\n\r\n$reflection_object = new ReflectionObject($object);\r\n$method = $reflection_object-&gt;getMethod(\"getAttribute2\");\r\n\r\ntry {\r\n\t$method-&gt;setAccessible(true);\r\n\techo $method-&gt;invoke($object);\r\n\t\r\n} catch (ReflectionException $e) {\r\n\techo \"Forbidden!\";\r\n}<\/pre>\n<p>We now get the number \u201c36\u201d as an output, as declared in our class. Using <strong>setAccessible()<\/strong>, the method\u2019s private behavior can be deactivated for its further execution.<\/p>\n<p>However, this is generally not recommended in practice, as there are usually reasons why some methods have been defined as private. One possible use of such techniques could be interesting for unit testing, for example.<\/p>\n<h3>Another example: Entities object with auto-fill<\/h3>\n<p>With this example, we would now like to show you how to use the reflection API in practice. To illustrate this accordingly, we will use an entity object, as you have already seen with many frameworks.<\/p>\n<p>To do so, we first build a base element from which we can later derive our individual entities. We assume that each entity has the following attributes (based on the Laravel framework):<\/p>\n<ul>\n<li>id<\/li>\n<li>createdAt<\/li>\n<li>updatedAt<\/li>\n<li>deletedAt<\/li>\n<\/ul>\n<pre class=\"lang:php decode:true\">\/**\r\n * Class BaseElement\r\n *\/\r\nabstract class BaseElement {\r\n\r\n\t\/**\r\n\t * @var int $id\r\n\t *\/\r\n\tprivate $id;\r\n\r\n\t\/**\r\n\t * @var \\DateTime $createdAt\r\n\t *\/\r\n\tprivate $createdAt;\r\n\r\n\t\/**\r\n\t * @var \\DateTime $updatedAt\r\n\t *\/\r\n\tprivate $updatedAt;\r\n\r\n\t\/**\r\n\t * @var \\DateTime $deletedAt\r\n\t *\/\r\n\tprivate $deletedAt;\r\n\r\n\r\n\t\/**\r\n\t * @var array\r\n\t *\/\r\n\tprivate $_hidden = [ 'deleted_at' ];\r\n\r\n\r\n\t\/**\r\n\t * BaseElement constructor.\r\n\t *\r\n\t * @param array $data\r\n\t *\/\r\n\tpublic function __construct( $data = null ) {\r\n\t\t\r\n\t}\r\n\r\n\r\n\r\n\t\/**\r\n\t * Returns the ID.\r\n\t *\r\n\t * @return int\r\n\t *\/\r\n\tpublic function getId() {\r\n\t\treturn $this-&gt;id;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Set the ID.\r\n\t *\r\n\t * @param int $id\r\n\t *\/\r\n\tpublic function setId( int $id ) {\r\n\t\t$this-&gt;id = $id;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Returns the creation date.\r\n\t *\r\n\t * @return \\DateTime\r\n\t *\/\r\n\tpublic function getCreatedAt() {\r\n\t\treturn $this-&gt;createdAt;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Set the creation date.\r\n\t *\r\n\t * @param \\DateTime $createdAt\r\n\t *\/\r\n\tpublic function setCreatedAt( $createdAt ) {\r\n\t\t$this-&gt;createdAt = $createdAt;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Returns the update date.\r\n\t *\r\n\t * @return \\DateTime\r\n\t *\/\r\n\tpublic function getUpdatedAt() {\r\n\t\treturn $this-&gt;updatedAt;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Set the update date.\r\n\t *\r\n\t * @param \\DateTime $updatedAt\r\n\t *\/\r\n\tpublic function setUpdatedAt( $updatedAt ) {\r\n\t\t$this-&gt;updatedAt = $updatedAt;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Returns the delete date.\r\n\t *\r\n\t * @return \\DateTime|null\r\n\t *\/\r\n\tpublic function getDeletedAt() {\r\n\t\treturn $this-&gt;deletedAt;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Set the delete date.\r\n\t *\r\n\t * @param \\DateTime|null $deletedAt\r\n\t *\/\r\n\tpublic function setDeletedAt( $deletedAt ) {\r\n\t\t$this-&gt;deletedAt = $deletedAt;\r\n\t}\r\n\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h4>Implementing auto-fill<\/h4>\n<p>We now have a base class with four attributes, each with the associated getter and setter methods. In the next step, we ensure that a data array can be transferred in the constructor, which then automatically determines and executes the corresponding setter methods.<\/p>\n<p>For this we write two helper classes: one for the string operations concerning the conversion from and to camel-case, as well as one for the type-casting:<\/p>\n<pre class=\"lang:php decode:true\">class StringHelper {\r\n\r\n\t\/**\r\n\t * Translates a camel case string into a string with\r\n\t * underscores (e.g. firstName -&gt; first_name)\r\n\t *\r\n\t * @param string $str String in camel case format\r\n\t *\r\n\t * @return string $str Translated into underscore format\r\n\t *\/\r\n\tpublic static function fromCamelCase( $str ) {\r\n\t\t$str[0] = strtolower( $str[0] );\r\n\t\t$func   = create_function( '$c', 'return \"_\" . strtolower($c[1]);' );\r\n\r\n\t\treturn preg_replace_callback( '\/([A-Z])\/', $func, $str );\r\n\t}\r\n\r\n\t\/**\r\n\t * Translates a string with underscores\r\n\t * into camel case (e.g. first_name -&gt; firstName)\r\n\t *\r\n\t * @param string $str String in underscore format\r\n\t * @param bool $capitalise_first_char If true, capitalise the first char in $str\r\n\t *\r\n\t * @return string $str translated into camel caps\r\n\t *\/\r\n\tpublic static function toCamelCase( $str, $capitalise_first_char = false ) {\r\n\t\tif ( $capitalise_first_char ) {\r\n\t\t\t$str[0] = strtoupper( $str[0] );\r\n\t\t}\r\n\t\t$func = create_function( '$c', 'return strtoupper($c[1]);' );\r\n\r\n\t\treturn preg_replace_callback( '\/_([a-z])\/', $func, $str );\r\n\t}\r\n\r\n}<\/pre>\n<pre class=\"lang:php decode:true \">class IoHelper {\r\n\r\n\t\/**\r\n\t * Helper function for casting variables into desired types.\r\n\t *\r\n\t * @param $value\r\n\t * @param string $type\r\n\t *\r\n\t * @return float|int|bool|string\r\n\t *\/\r\n\tpublic static function castValue( $value, $type = 'string' ) {\r\n\t\t$type = strtolower($type);\r\n\r\n\t\tswitch ( $type ) {\r\n\t\t\tcase 'string':\r\n\t\t\t\t$value = (string) $value;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'int':\r\n\t\t\tcase 'integer':\r\n\t\t\t\t$value = (int) $value;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'double':\r\n\t\t\t\t$value = (double) $value;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'float':\r\n\t\t\t\t$value = (float) $value;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'bool':\r\n\t\t\tcase 'boolean':\r\n\t\t\t\t$value = (bool) $value;\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\t$value = $value;\r\n\t\t}\r\n\r\n\t\treturn $value;\r\n\t}\r\n\r\n}<\/pre>\n<p>Now let\u2019s once again focus on our base class. To do so, we extend the constructor as follows:<\/p>\n<pre class=\"lang:php decode:true \">\/**\r\n * BaseElement constructor.\r\n *\r\n * @param array $data\r\n *\/\r\npublic function __construct( $data = null ) {\r\n\t\/\/ check if fill data was provided\r\n\tif ( $data ) {\r\n\r\n\t\t\/\/ cast object into array if it's an object\r\n\t\tif ( is_object( $data ) ) {\r\n\t\t\t$data = (array) $data;\r\n\t\t}\r\n\r\n\t\t\/\/ iterate over data array\r\n\t\tforeach ( $data as $key =&gt; $value ) {\r\n\r\n\t\t\t\/\/ build up name for equivalent setter-function\r\n\t\t\t$setterFunction = 'set' . StringHelper::toCamelCase( $key, true );\r\n\r\n\t\t\t\/\/ check if desired setter-functions exists and if so, execute it\r\n\t\t\tif ( method_exists( $this, $setterFunction ) ) {\r\n\r\n\t\t\t\t\/\/ get reflection method\r\n\t\t\t\t$reflectionMethod = new \\ReflectionMethod( $this, $setterFunction );\r\n\r\n\t\t\t\t\/\/ get parameters for reflection method\r\n\t\t\t\t$reflectionParameters = $reflectionMethod-&gt;getParameters();\r\n\r\n\t\t\t\t\/\/ check if desired parameter at position 0 exists\r\n\t\t\t\tif ( isset( $reflectionParameters[0] ) ) {\r\n\r\n\t\t\t\t\t\/\/ detect desired data type by reading doc-comments\r\n\t\t\t\t\t$type        = strtolower( (string) $reflectionParameters[0]-&gt;getType() );\r\n\t\t\t\t\t$castedValue = IoHelper::castValue( $value, $type );\r\n\r\n\t\t\t\t\t\/\/ call setter-function with casted parameter\r\n\t\t\t\t\t$this-&gt;$setterFunction( $castedValue );\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n}<\/pre>\n<p>It is relatively easy to explain what happens here: it checks whether a data array has been transferred. If this is the case, it then checks whether it is an object (as would be the case, for example, with the Laravel eloquent ORM). If so, it is converted into an array. In the next step, a <strong>foreach<\/strong> loop is used to iterate via each individual transferred attribute in the key value style. Since the index is known, and it should represent the relevant attribute, we assume that the associated setter function is named in the \u201c<strong>set &lt;AttributName&gt;<\/strong>\u201d style.<\/p>\n<p>If such a setter method actually exists in the current object instance, we instantiate it using <strong>ReflectionMethod()<\/strong>. Theoretically, it would already be possible to use it directly. However, we must first cast the transferred value accordingly to ensure that it matches the expected data type of the respective setter method.<\/p>\n<p>To do so, <strong>getParameters()<\/strong> is first used to read out which parameters can be transferred to the respective setter method. We assume in this case that each of these methods can accept exactly one parameter, i.e., the value to be set. If this parameter is defined, then the expected data type, which was defined via the PHP annotations, is returned using <strong>getType()<\/strong>. We now transfer this determined target data type to our helper class and get the correspondingly casted variable back.<\/p>\n<p>In the last step, we now activate the setter method via regular access and transfer the previously casted value to it as a parameter. In principle, we have now implemented our core functionality regarding auto-fill.<\/p>\n<h4>Outputting data<\/h4>\n<p>To now access data within our base class using the respective getter method, we write a little private helper method:<\/p>\n<pre class=\"lang:php decode:true \">\/**\r\n * Tries to find an adequate Getter-function for the specified attribute key, and returns its value.\r\n *\r\n * @param $key\r\n *\r\n * @return null\r\n *\/\r\nprivate function getElementByKey( $key ) {\r\n\t\/\/ build up name for equivalent setter-function\r\n\t$getterFunction = 'get' . StringHelper::toCamelCase( $key, true );\r\n\r\n\t\/\/ check if desired setter-functions exists and if so, execute it\r\n\tif ( method_exists( $this, $getterFunction ) ) {\r\n\r\n\t\t\/\/ get reflection method\r\n\t\t$reflectionMethod     = new \\ReflectionMethod( $this, $getterFunction );\r\n\t\t$reflectionMethodName = $reflectionMethod-&gt;getName();\r\n\r\n\t\treturn $this-&gt;$reflectionMethodName();\r\n\t}\r\n\r\n\treturn null;\r\n}<\/pre>\n<p>We can transfer the name of the desired attribute to it as a parameter. Similar to the way we set the values previously, we determine the name of the associated getter method assuming that it was defined in the \u201c<strong>get &lt;AttributName&gt;<\/strong>\u201d style.<\/p>\n<p>If the method exists in the current object context, it is executed using <strong>ReflectionMethod()<\/strong>, and as a result the value of the desired attribute is returned.<\/p>\n<p>In order for us to dynamically enable the output of all attributes, we must know which attributes are generally present in the activated class as well as in the base class (as parent class). To do so, we define a method named <strong>getDocument()<\/strong>, which does exactly that:<\/p>\n<pre class=\"lang:php decode:true \">\/**\r\n * Build up the public exposed data array.\r\n *\r\n * @param bool $buildRelations\r\n *\r\n * @return array\r\n *\/\r\npublic function getDocument() {\r\n\t$reflectionClass = new \\ReflectionClass( $this );\r\n\t$properties      = [];\r\n\r\n\t\/\/ determine properties of parent class from current context\r\n\t$this-&gt;buildPropertyArray( $reflectionClass-&gt;getParentClass()-&gt;getProperties(), $properties );\r\n\r\n\t\/\/ determine properties of current class\r\n\t$this-&gt;buildPropertyArray( $reflectionClass-&gt;getProperties(), $properties );\r\n\r\n\t\/\/ build up data array\r\n\t$data = [];\r\n\tforeach ( $properties as $property ) {\r\n\t\tif ( ! in_array( StringHelper::fromCamelCase( $property ), $this-&gt;_hidden ) ) {\r\n\t\t\t$data[ $property ] = $this-&gt;getElementByKey( $property );\r\n\t\t}\r\n\t}\r\n\r\n\treturn $data;\r\n}\r\n\r\n\r\n\r\n\/**\r\n * Internal helper function for extracting valid (public) attributes from ReflectionProperty() array.\r\n *\r\n * @param $reflectionProperties\r\n * @param $data\r\n *\/\r\nprivate function buildPropertyArray( $reflectionProperties, &amp;$data ) {\r\n\tforeach ( $reflectionProperties as $property ) {\r\n\t\t$propertyName = $property-&gt;getName();\r\n\r\n\t\tif ( substr( $propertyName, 0, 1 ) == '_' ) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t$data[] = $property-&gt;getName();\r\n\t}\r\n}<\/pre>\n<p>The auxiliary method <strong>buildPropertyArray()<\/strong> mainly helps to avoid duplicate code and also to ignore attributes that begin with an (&#8222;_\u201d) underscore. Attributes that begin with an underscore are not exported externally via <strong>getDocument()<\/strong> in this case, and therefore remain confidential.<\/p>\n<h4>Deriving own entities<\/h4>\n<p>To derive your own entity classes using the base class, you merely have to create a new class with the desired name which will inherit data from our previously created base class.<\/p>\n<p>Individual attributes can now be defined within it according to the same principle\u2014nothing else is necessary here.<\/p>\n<pre class=\"lang:php decode:true\">\/**\r\n * Class Dummy\r\n *\/\r\nclass Dummy extends BaseElement {\r\n\r\n\r\n\t\/**\r\n\t * @var string $title\r\n\t *\/\r\n\tprivate $title;\r\n\r\n\r\n\r\n\t\/**\r\n\t * Returns the title.\r\n\t *\r\n\t * @return string\r\n\t *\/\r\n\tpublic function getTitle() {\r\n\t\treturn $this-&gt;title;\r\n\t}\r\n\r\n\r\n\t\/**\r\n\t * Set the title.\r\n\t *\r\n\t * @param string $title\r\n\t *\/\r\n\tpublic function setTitle( string $title ) {\r\n\t\t$this-&gt;title = $title;\r\n\t}\r\n\r\n}<\/pre>\n<p>To test our entity class, we define a small data array using a few test values. This should simulate an external data source in our case.<\/p>\n<pre class=\"lang:php decode:true \">$data = [\r\n\t\"id\"\t=&gt; 14,\r\n\t\"title\"\t=&gt; \"Lorem ipsum\",\r\n];<\/pre>\n<p>In the next step, we initialize our newly created entity class using this data array and can then export the full result using <strong>getDocument()<\/strong>:<\/p>\n<pre class=\"lang:php decode:true\">$entity = new Dummy( $data );\r\n\r\nprint_r( $entity-&gt;getDocument() );<\/pre>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>The program can use reflection to operate in an \u201cintelligent\u201d manner in modern software development since it is able to analyze and even modify the characteristics of it own functions during runtime.<\/p>\n<p>However, the implementation of reflection in PHP is so broad that we have demonstrated only a limited number of the possibilities here. There are countless other functions to further break down the program code.<\/p>\n<p>In summary, we can see that reflection provides you with a very powerful technology that can really help you accomplish a great deal. Actually, we are using it a lot at Anexia.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reflection in software development means that a program knows its own structure &amp; can also modify it. Here we explain how it works in practical terms.<\/p>\n","protected":false},"author":15,"featured_media":2961,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1135],"tags":[1329,1614,1636,1327,1638],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Reflection in PHP projects - ANEXIA Blog<\/title>\n<meta name=\"description\" content=\"Reflection in software development means that a program knows its own structure &amp; can also modify it. Here we explain how it works in practical terms.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Reflection in PHP projects - ANEXIA Blog\" \/>\n<meta property=\"og:description\" content=\"Reflection in software development means that a program knows its own structure &amp; can also modify it. Here we explain how it works in practical terms.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/\" \/>\n<meta property=\"og:site_name\" content=\"ANEXIA Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/anexiagmbh\/\" \/>\n<meta property=\"article:published_time\" content=\"2018-04-11T07:10:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-04-21T11:40:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"672\" \/>\n\t<meta property=\"og:image:height\" content=\"372\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Manuel Wutte\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:site\" content=\"@_ANEXIA\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manuel Wutte\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"14\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/\",\"url\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/\",\"name\":\"Reflection in PHP projects - ANEXIA Blog\",\"isPartOf\":{\"@id\":\"https:\/\/anexia.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"datePublished\":\"2018-04-11T07:10:19+00:00\",\"dateModified\":\"2022-04-21T11:40:22+00:00\",\"author\":{\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\"},\"description\":\"Reflection in software development means that a program knows its own structure & can also modify it. Here we explain how it works in practical terms.\",\"breadcrumb\":{\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage\",\"url\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"contentUrl\":\"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg\",\"width\":672,\"height\":372},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/anexia.com\/blog\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Reflection in PHP projects\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/anexia.com\/blog\/#website\",\"url\":\"https:\/\/anexia.com\/blog\/\",\"name\":\"ANEXIA Blog\",\"description\":\"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/anexia.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de\",\"name\":\"Manuel Wutte\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g\",\"caption\":\"Manuel Wutte\"},\"url\":\"https:\/\/anexia.com\/blog\/author\/mwu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Reflection in PHP projects - ANEXIA Blog","description":"Reflection in software development means that a program knows its own structure & can also modify it. Here we explain how it works in practical terms.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/","og_locale":"de_DE","og_type":"article","og_title":"Reflection in PHP projects - ANEXIA Blog","og_description":"Reflection in software development means that a program knows its own structure & can also modify it. Here we explain how it works in practical terms.","og_url":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/","og_site_name":"ANEXIA Blog","article_publisher":"https:\/\/www.facebook.com\/anexiagmbh\/","article_published_time":"2018-04-11T07:10:19+00:00","article_modified_time":"2022-04-21T11:40:22+00:00","og_image":[{"width":672,"height":372,"url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","type":"image\/jpeg"}],"author":"Manuel Wutte","twitter_card":"summary_large_image","twitter_creator":"@_ANEXIA","twitter_site":"@_ANEXIA","twitter_misc":{"Verfasst von":"Manuel Wutte","Gesch\u00e4tzte Lesezeit":"14\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/","url":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/","name":"Reflection in PHP projects - ANEXIA Blog","isPartOf":{"@id":"https:\/\/anexia.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage"},"image":{"@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage"},"thumbnailUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","datePublished":"2018-04-11T07:10:19+00:00","dateModified":"2022-04-21T11:40:22+00:00","author":{"@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de"},"description":"Reflection in software development means that a program knows its own structure & can also modify it. Here we explain how it works in practical terms.","breadcrumb":{"@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#primaryimage","url":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","contentUrl":"https:\/\/anexia.com\/blog\/wp-content\/uploads\/2017\/09\/ManuelWutte-Blog-Teaser.jpg","width":672,"height":372},{"@type":"BreadcrumbList","@id":"https:\/\/anexia.com\/blog\/en\/reflection-in-php-projects\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/anexia.com\/blog\/de\/"},{"@type":"ListItem","position":2,"name":"Reflection in PHP projects"}]},{"@type":"WebSite","@id":"https:\/\/anexia.com\/blog\/#website","url":"https:\/\/anexia.com\/blog\/","name":"ANEXIA Blog","description":"[:de] ANEXIA Blog - Technischen Themen, Anexia News und Insights [:]","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/anexia.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/926f6b9e5aeed88b145cf86d87fd09de","name":"Manuel Wutte","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/anexia.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9528a61f48f4294cd5f7cd8a4141bd55?s=96&d=mm&r=g","caption":"Manuel Wutte"},"url":"https:\/\/anexia.com\/blog\/author\/mwu\/"}]}},"lang":"en","translations":{"en":6693,"de":3430},"amp_enabled":true,"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6693"}],"collection":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/comments?post=6693"}],"version-history":[{"count":1,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6693\/revisions"}],"predecessor-version":[{"id":6696,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/posts\/6693\/revisions\/6696"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media\/2961"}],"wp:attachment":[{"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/media?parent=6693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/categories?post=6693"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/anexia.com\/blog\/wp-json\/wp\/v2\/tags?post=6693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}