{"id":198723,"date":"2021-03-10T17:00:37","date_gmt":"2021-03-10T14:00:37","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/"},"modified":"2021-03-10T17:00:37","modified_gmt":"2021-03-10T14:00:37","slug":"approaches-to-creating-typed-arrays-in-php-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/","title":{"rendered":"#Approaches to Creating Typed Arrays in PHP \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a2b4cc41b91d\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a2b4cc41b91d\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Identifying_the_Problem\" >Identifying the Problem<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Adding_Type_Consistency_with_Variadic_Arguments\" >Adding Type Consistency with Variadic Arguments<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Limitations_of_Variadic_Arguments\" >Limitations of Variadic Arguments<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Collection_Classes\" >Collection Classes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Making_Collections_More_Array-Like\" >Making Collections More Array-Like<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/buradabiliyorum.com\/en\/approaches-to-creating-typed-arrays-in-php-cloudsavvy-it\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>&#8220;#<a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">App<\/a>roaches to Creating Typed Arrays in PHP \u2013 CloudSavvy IT&#8221;<\/strong><\/p>\n<div id=\"article-content-area\">\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-4047\" src=\"https:\/\/www.cloudsavvyit.com\/thumbcache\/0\/0\/b835749967babe94be45e3edd2508d9c\/p\/uploads\/2017\/08\/1ac500da.png\" alt=\"PHP Logo\" width=\"1400\" height=\"600\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>PHP doesn\u2019t let you define typed arrays. Any array can contain any value, which makes it tricky to enforce consistency in your codebase. Here are a few workarounds to help you create typed collections of objects using existing PHP features.<\/p>\n<h2 id=\"identifying-the-problem\"><span class=\"ez-toc-section\" id=\"Identifying_the_Problem\"><\/span>Identifying the Problem<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>PHP arrays are a very flexible data structure. You can add whatever you like to an array, ranging from scalar values to complex objects:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"re0\">$arr<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">[<\/span>\n    <span class=\"st0\">\"foobar\"<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"nu0\">123<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>In practice, it\u2019s rare you\u2019d actually want an array with such a varied range of values. It\u2019s more likely that your arrays will contain multiple instances of the same kind of value.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"re0\">$times<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">[<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>You might then create a method which acts on all the values within your array:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\">final <span class=\"kw2\">class<\/span> Stopwatch <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">protected<\/span> <span class=\"kw3\">array<\/span> <span class=\"re0\">$laps<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> recordLaps<span class=\"br0\">(<\/span><span class=\"kw3\">array<\/span> <span class=\"re0\">$times<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> void <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">foreach<\/span> <span class=\"br0\">(<\/span><span class=\"re0\">$times<\/span> <span class=\"kw1\">as<\/span> <span class=\"re0\">$time<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n            <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">laps<\/span><span class=\"br0\">[<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$time<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">getTimestamp<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n        <span class=\"br0\">}<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>This code iterates over the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/www.php.net\/manual\/en\/class.datetimeinterface.php\"><code>DateTimeInterface<\/code> instances<\/a> in <code>$times<\/code>. The Unix timestamp representation of the time (seconds measured as an integer) is then stored into <code>$laps<\/code>.<\/p>\n<p>The trouble with this code is it makes an <em>assumption<\/em> that <code>$times<\/code> is comprised wholly of <code>DateTimeInterface<\/code> instances. There\u2019s nothing to guarantee this is the case so a caller could still pass an array of mixed values. If one of the values didn\u2019t implement <code>DateTimeInterface<\/code>, the call to <code>getTimestamp()<\/code> would be illegal and a runtime error would occur.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">new<\/span> Stopwatch<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"co1\">\/\/ OK<\/span>\n<span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">recordLaps<\/span><span class=\"br0\">(<\/span><span class=\"br0\">[<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">]<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"co1\">\/\/ Crash!<\/span>\n<span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">recordLaps<\/span><span class=\"br0\">(<\/span><span class=\"br0\">[<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"nu0\">123<\/span>     <span class=\"co1\">\/\/ can't call `getTimestamp()` on an integer!<\/span>\n<span class=\"br0\">]<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2 id=\"adding-type-consistency-with-variadic-arguments\"><span class=\"ez-toc-section\" id=\"Adding_Type_Consistency_with_Variadic_Arguments\"><\/span>Adding Type Consistency with Variadic Arguments<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ideally the issue would be resolved by specifying that the <code>$times<\/code> array can only contain <code>DateTimeInterface<\/code> instances. As PHP lacks support for typed arrays, we must look to alternative language features instead.<\/p>\n<p>The first option is to use variadic arguments and unpack the <code>$times<\/code> array before it\u2019s passed to <code>recordLaps()<\/code>. Variadic arguments allow a function to accept an unknown number of arguments which are then made available as a single array. Importantly for our use case, you may typehint variadic arguments as normal. Each argument passed in must then be of the given type.<\/p>\n<p>Variadic arguments are commonly used for mathematical functions. Here\u2019s a simple example that sums every argument it\u2019s given:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"kw2\">function<\/span> sumAll<span class=\"br0\">(<\/span>int <span class=\"sy0\">...<\/span><span class=\"re0\">$numbers<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n    <span class=\"kw1\">return<\/span> <span class=\"kw3\">array_sum<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$numbers<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"kw1\">echo<\/span> sumAll<span class=\"br0\">(<\/span><span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">3<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">4<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">5<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>     <span class=\"co1\">\/\/ emits 15<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><code>sumAll()<\/code> is not passed an array. Instead, it receives multiple arguments which PHP combines into the <code>$numbers<\/code> array. The <code>int<\/code> typehint means each value must be an integer. This acts as a guarantee that <code>$numbers<\/code> will only consist of integers. We can now apply this to the stopwatch example:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\">final <span class=\"kw2\">class<\/span> Stopwatch <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">protected<\/span> <span class=\"kw3\">array<\/span> <span class=\"re0\">$laps<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> recordLaps<span class=\"br0\">(<\/span>DateTimeInterface <span class=\"sy0\">...<\/span><span class=\"re0\">$times<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> void <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">foreach<\/span> <span class=\"br0\">(<\/span><span class=\"re0\">$times<\/span> <span class=\"kw1\">as<\/span> <span class=\"re0\">$time<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n            <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">laps<\/span><span class=\"br0\">[<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$time<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">getTimestamp<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n        <span class=\"br0\">}<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">new<\/span> Stopwatch<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">recordLaps<\/span><span class=\"br0\">(<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>It\u2019s no longer possible to pass unsupported types into <code>recordLaps()<\/code>. Attempts to do so will be surfaced much earlier, before the <code>getTimestamp()<\/code> call is attempted.<\/p>\n<p>If you\u2019ve already got an array of times to pass to <code>recordLaps()<\/code>, you\u2019ll need to unpack it with the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/www.php.net\/manual\/en\/migration56.new-features.php\">splat operator<\/a> (<code>...<\/code>) when you call the method. Trying to pass it directly will fail \u2013 it\u2019d be treated as one of the variadic times, which are required to be an <code>int<\/code> and not an <code>array<\/code>.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"re0\">$times<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">[<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> DateTimeImmutable<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"re0\">$stopwatch<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">recordLaps<\/span><span class=\"br0\">(<\/span><span class=\"sy0\">...<\/span><span class=\"re0\">$times<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2 id=\"limitations-of-variadic-arguments\"><span class=\"ez-toc-section\" id=\"Limitations_of_Variadic_Arguments\"><\/span>Limitations of Variadic Arguments<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Variadic arguments can be a great help when you need to pass an array of items to a function. However, there are some restrictions on how they can be used.<\/p>\n<p>The most significant limitation is that you can only use one set of variadic arguments per function. This means each function can accept only one \u201ctyped\u201d array. In addition, the variadic argument must be defined last, after any regular arguments.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"kw2\">function<\/span> variadic<span class=\"br0\">(<\/span>string <span class=\"re0\">$something<\/span><span class=\"sy0\">,<\/span> DateTimeInterface <span class=\"sy0\">...<\/span><span class=\"re0\">$times<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>By nature, variadic arguments can only be used with functions. This means they can\u2019t help you out when you need to <em>store<\/em> an array as a property, or return it from a function. We can see this in the stopwatch code \u2013 the <code>Stopwatch<\/code> class has a <code>laps<\/code> array which is meant to store only integer timestamps. There\u2019s currently no way we can enforce this is the case.<\/p>\n<h2 id=\"collection-classes\"><span class=\"ez-toc-section\" id=\"Collection_Classes\"><\/span>Collection Classes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In these circumstances a different approach must be selected. One way to create something close to a \u201ctyped array\u201d in userland PHP is to write a dedicated collection class:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\">final <span class=\"kw2\">class<\/span> User <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">protected<\/span> string <span class=\"re0\">$Email<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> getEmail<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> string <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Email<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span>\n\u00a0\nfinal <span class=\"kw2\">class<\/span> UserCollection <span class=\"kw2\">implements<\/span> IteratorAggregate <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">private<\/span> <span class=\"kw3\">array<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> __construct<span class=\"br0\">(<\/span>User <span class=\"sy0\">...<\/span><span class=\"re0\">$Users<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> getIterator<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> ArrayIterator <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"kw2\">new<\/span> ArrayIterator<span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>The <code>UserCollection<\/code> class can now be used anywhere you\u2019d normally expect an array of <code>User<\/code> instances. <code>UserCollection<\/code> uses variadic arguments to accept a <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/watch-movies-tv-seriess\/\" data-internallinksmanager029f6b8e52c=\"8\" title=\"Watch Movies &amp; TV Series\" target=\"_blank\" rel=\"noopener\">series<\/a> of <code>User<\/code> instances in its constructor. Although the <code>$Users<\/code> property has to be typehinted as the generic <code>array<\/code>, it\u2019s guaranteed to consist wholly of user instances as it\u2019s only written to in the constructor.<\/p>\n<p>It may seem tempting to provide a <code>get() : array<\/code> method which exposes all the collection\u2019s items. This should be avoided as it brings us back to the vague <code>array<\/code> typehint problem. Instead, the collection is made iterable so consumers can use it in a <code>foreach<\/code> loop. In this way, we\u2019ve managed to create a typehint-able \u201carray\u201d which our code can safely assume contains only users.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\"><span class=\"kw2\">function<\/span> sendMailToUsers<span class=\"br0\">(<\/span>UserCollection <span class=\"re0\">$Users<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> void <span class=\"br0\">{<\/span>\n    <span class=\"kw1\">foreach<\/span> <span class=\"br0\">(<\/span><span class=\"re0\">$Users<\/span> <span class=\"kw1\">as<\/span> <span class=\"re0\">$User<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"kw3\">mail<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$user<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">getEmail<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">\"Test Email\"<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">\"Hello World!\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"re0\">$users<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">new<\/span> UserCollection<span class=\"br0\">(<\/span><span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span> <span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\nsendMailToUsers<span class=\"br0\">(<\/span><span class=\"re0\">$users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2 id=\"making-collections-more-array-like\"><span class=\"ez-toc-section\" id=\"Making_Collections_More_Array-Like\"><\/span>Making Collections More Array-Like<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Collection classes solve the typehinting problem but do mean you lose some of the <em>useful<\/em> functionality of arrays. Built-in PHP functions like <code>count()<\/code> and <code>isset()<\/code> won\u2019t work with your custom collection class.<\/p>\n<p>Support for these functions can be added by implementing additional built-in interfaces. If you implement <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/www.php.net\/manual\/en\/class.countable.php\"><code>Countable<\/code><\/a>, your class will be usable with <code>count()<\/code>:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\">final <span class=\"kw2\">class<\/span> UserCollection <span class=\"kw2\">implements<\/span> Countable<span class=\"sy0\">,<\/span> IteratorAggregate <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">private<\/span> <span class=\"kw3\">array<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> __construct<span class=\"br0\">(<\/span>User <span class=\"sy0\">...<\/span><span class=\"re0\">$Users<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> <span class=\"kw3\">count<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> int <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"kw3\">count<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> getIterator<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> ArrayIterator <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"kw2\">new<\/span> ArrayIterator<span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"re0\">$users<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">new<\/span> UserCollection<span class=\"br0\">(<\/span><span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span> <span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">echo<\/span> <span class=\"kw3\">count<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>     <span class=\"co1\">\/\/ 2<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Implementing <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/www.php.net\/manual\/en\/class.arrayaccess.php\"><code>ArrayAccess<\/code><\/a> lets you access items in your collection using array syntax. It also enables the <code>isset()<\/code> and <code>unset()<\/code> functions. You need to implement four methods so PHP can interact with your items.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"php\">\n<pre class=\"de1\">final <span class=\"kw2\">class<\/span> UserCollection <span class=\"kw2\">implements<\/span> ArrayAccess<span class=\"sy0\">,<\/span> IteratorAggregate <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw2\">private<\/span> <span class=\"kw3\">array<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> __construct<span class=\"br0\">(<\/span>User <span class=\"sy0\">...<\/span><span class=\"re0\">$Users<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$Users<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> offsetExists<span class=\"br0\">(<\/span>mixed <span class=\"re0\">$offset<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> bool <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"kw3\">isset<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">[<\/span><span class=\"re0\">$offset<\/span><span class=\"br0\">]<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> offsetGet<span class=\"br0\">(<\/span>mixed <span class=\"re0\">$offset<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> User <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">[<\/span><span class=\"re0\">$offset<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> offsetSet<span class=\"br0\">(<\/span>mixed <span class=\"re0\">$offset<\/span><span class=\"sy0\">,<\/span> mixed <span class=\"re0\">$value<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> void <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span><span class=\"re0\">$value<\/span> instanceof User<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n            <span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">[<\/span><span class=\"re0\">$offset<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">=<\/span> <span class=\"re0\">$value<\/span><span class=\"sy0\">;<\/span>\n        <span class=\"br0\">}<\/span>\n        <span class=\"kw1\">else<\/span> <span class=\"kw1\">throw<\/span> <span class=\"kw2\">new<\/span> TypeError<span class=\"br0\">(<\/span><span class=\"st0\">\"Not a user!\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> offsetUnset<span class=\"br0\">(<\/span>mixed <span class=\"re0\">$offset<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> void <span class=\"br0\">{<\/span>\n        <span class=\"kw3\">unset<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">[<\/span><span class=\"re0\">$offset<\/span><span class=\"br0\">]<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw2\">public<\/span> <span class=\"kw2\">function<\/span> getIterator<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">:<\/span> ArrayIterator <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">return<\/span> <span class=\"kw2\">new<\/span> ArrayIterator<span class=\"br0\">(<\/span><span class=\"re0\">$this<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">Users<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"re0\">$users<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">new<\/span> UserCollection<span class=\"br0\">(<\/span>\n    <span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"st0\">\"example@example.com\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">,<\/span>\n    <span class=\"kw2\">new<\/span> User<span class=\"br0\">(<\/span><span class=\"st0\">\"hello@world.com\"<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"kw1\">echo<\/span> <span class=\"re0\">$users<\/span><span class=\"br0\">[<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">-&gt;<\/span> <span class=\"me1\">getEmail<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>   <span class=\"co1\">\/\/ hello@world.com<\/span>\n<span class=\"kw3\">var_dump<\/span><span class=\"br0\">(<\/span><span class=\"kw3\">isset<\/span><span class=\"br0\">(<\/span><span class=\"re0\">$users<\/span><span class=\"br0\">[<\/span><span class=\"nu0\">2<\/span><span class=\"br0\">]<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>     <span class=\"co1\">\/\/ false<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>You now have a class which can only contain <code>User<\/code> instances and which also looks and feels like an array. One point to note about <code>ArrayAccess<\/code> is the <code>offsetSet<\/code> implementation \u2013 as <code>$value<\/code> must be <code>mixed<\/code>, this could allow incompatible values to be added to your collection. We explicitly check the type of the passed <code>$value<\/code> to prevent this.<\/p>\n<h2 id=\"conclusion\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Recent PHP releases have evolved the language towards stronger typing and greater consistency. This doesn\u2019t yet extend to array elements though. Typehinting against <code>array<\/code> is often too relaxed but you can circumvent the limitations by building your own collection classes.<\/p>\n<p>When combined with variadic arguments, the collection pattern is a viable way to enforce the types of aggregate values in your code. You can typehint your collections and iterate over them knowing only one type of value will be present.\n<\/p><\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/10040\/approaches-to-creating-typed-arrays-in-php\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;#Approaches to Creating Typed Arrays in PHP \u2013 CloudSavvy IT&#8221; PHP doesn\u2019t let you define typed arrays. Any array can contain any value, which makes it tricky to enforce consistency in your codebase. Here are a few workarounds to help you create typed collections of objects using existing PHP features. Identifying the Problem PHP arrays&#8230;<\/p>\n","protected":false},"author":1,"featured_media":198724,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/thumbcache\/0\/0\/b835749967babe94be45e3edd2508d9c\/p\/uploads\/2017\/08\/1ac500da.png","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-198723","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/198723","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=198723"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/198723\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/198724"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=198723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=198723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=198723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}