<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/language.enumerations.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'uk',
  ),
  'this' => 
  array (
    0 => 'language.enumerations.backed.php',
    1 => 'Backed enumerations',
    2 => 'Backed enumerations',
  ),
  'up' => 
  array (
    0 => 'language.enumerations.php',
    1 => 'Enumerations',
  ),
  'prev' => 
  array (
    0 => 'language.enumerations.basics.php',
    1 => 'Basic enumerations',
  ),
  'next' => 
  array (
    0 => 'language.enumerations.methods.php',
    1 => 'Enumeration methods',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'en',
    'path' => 'language/enumerations.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="language.enumerations.backed" class="sect1">
  <h2 class="title">Backed enumerations</h2>

  <p class="para">
   By default, Enumerated Cases have no scalar equivalent. They are simply singleton objects. However,
   there are ample cases where an Enumerated Case needs to be able to round-trip to a database or
   similar datastore, so having a built-in scalar (and thus trivially serializable) equivalent defined
   intrinsically is useful.
  </p>

  <p class="para">To define a scalar equivalent for an Enumeration, the syntax is as follows:</p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">enum </span><span style="color: #0000BB">Suit</span><span style="color: #007700">: </span><span style="color: #0000BB">string<br /></span><span style="color: #007700">{<br />    case </span><span style="color: #0000BB">Hearts </span><span style="color: #007700">= </span><span style="color: #DD0000">'H'</span><span style="color: #007700">;<br />    case </span><span style="color: #0000BB">Diamonds </span><span style="color: #007700">= </span><span style="color: #DD0000">'D'</span><span style="color: #007700">;<br />    case </span><span style="color: #0000BB">Clubs </span><span style="color: #007700">= </span><span style="color: #DD0000">'C'</span><span style="color: #007700">;<br />    case </span><span style="color: #0000BB">Spades </span><span style="color: #007700">= </span><span style="color: #DD0000">'S'</span><span style="color: #007700">;<br />}<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>


  <p class="para">
   A case that has a scalar equivalent is called a Backed Case, as it is &quot;Backed&quot;
   by a simpler value. An Enum that contains all Backed Cases is called a &quot;Backed Enum.&quot;
   A Backed Enum may contain only Backed Cases. A Pure Enum may contain only Pure Cases.
  </p>

  <p class="para">
   A Backed Enum may be backed by types of <code class="literal">int</code> or <code class="literal">string</code>,
   and a given enumeration supports only a single type at a time (that is, no union of <code class="literal">int|string</code>).
   If an enumeration is marked as having a scalar equivalent, then all cases must have a unique
   scalar equivalent defined explicitly. There are no auto-generated scalar equivalents
   (e.g., sequential integers). Backed cases must be unique; two backed enum cases may
   not have the same scalar equivalent. However, a constant may refer to a case, effectively
   creating an alias. See <a href="language.enumerations.constants.php" class="link">Enumeration constants</a>.
  </p>

  <p class="para">
   The equivalent values may be a constant scalar expression.
   Prior to PHP 8.2.0, the equivalent values had to be literals or literal expressions.
   This means that constants and constant expressions were not supported.
   That is, <code class="code">1 + 1</code> was allowed, but <code class="code">1 + SOME_CONST</code> was not.
  </p>

  <p class="para">
   Backed Cases have an additional read-only property, <code class="literal">value</code>, which is the value
   specified in the definition.
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">print </span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Clubs</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">// Prints "C"<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>


  <p class="para">
   In order to enforce the <code class="literal">value</code> property as read-only, a variable cannot
   be assigned as a reference to it. That is, the following throws an error:
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$suit </span><span style="color: #007700">= </span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Clubs</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$ref </span><span style="color: #007700">= &amp;</span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">// Error: Cannot acquire reference to property Suit::$value<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>


  <p class="para">
   Backed enums implement an internal <span class="interfacename"><a href="class.backedenum.php" class="interfacename">BackedEnum</a></span> interface,
   which exposes two additional methods:
  </p>

  <ul class="simplelist">
   <li>
    <code class="literal">from(int|string): self</code> will take a scalar and return the corresponding
    Enum Case. If one is not found, it will throw a <span class="classname"><a href="class.valueerror.php" class="classname">ValueError</a></span>. This is mainly
    useful in cases where the input scalar is trusted and a missing enum value should be
    considered an application-stopping error.
   </li>
   <li>
    <code class="literal">tryFrom(int|string): ?self</code> will take a scalar and return the
    corresponding Enum Case. If one is not found, it will return <code class="literal">null</code>.
    This is mainly useful in cases where the input scalar is untrusted and the caller wants
    to implement their own error handling or default-value logic.
   </li>
  </ul>

  <p class="para">
   The <code class="literal">from()</code> and <code class="literal">tryFrom()</code> methods follow standard
   weak/strong typing rules. In weak typing mode, passing an integer or string is acceptable
   and the system will coerce the value accordingly. Passing a float will also work and be
   coerced. In strict typing mode, passing an integer to <code class="literal">from()</code> on a
   string-backed enum (or vice versa) will result in a <span class="classname"><a href="class.typeerror.php" class="classname">TypeError</a></span>,
   as will a float in all circumstances. All other parameter types will throw a TypeError
   in both modes.
  </p>

  <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$record </span><span style="color: #007700">= </span><span style="color: #0000BB">get_stuff_from_database</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">);<br />print </span><span style="color: #0000BB">$record</span><span style="color: #007700">[</span><span style="color: #DD0000">'suit'</span><span style="color: #007700">];<br /><br /></span><span style="color: #0000BB">$suit </span><span style="color: #007700">=  </span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">from</span><span style="color: #007700">(</span><span style="color: #0000BB">$record</span><span style="color: #007700">[</span><span style="color: #DD0000">'suit'</span><span style="color: #007700">]);<br /></span><span style="color: #FF8000">// Invalid data throws a ValueError: "X" is not a valid scalar value for enum "Suit"<br /></span><span style="color: #007700">print </span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$suit </span><span style="color: #007700">= </span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">tryFrom</span><span style="color: #007700">(</span><span style="color: #DD0000">'A'</span><span style="color: #007700">) ?? </span><span style="color: #0000BB">Suit</span><span style="color: #007700">::</span><span style="color: #0000BB">Spades</span><span style="color: #007700">;<br /></span><span style="color: #FF8000">// Invalid data returns null, so Suit::Spades is used instead.<br /></span><span style="color: #007700">print </span><span style="color: #0000BB">$suit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">value</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
  </div>


  <p class="para">Manually defining a <code class="literal">from()</code> or <code class="literal">tryFrom()</code> method on a Backed Enum will result in a fatal error.</p>

  </div><?php manual_footer($setup); ?>