/**
  * Given the patterns for generating the names and aliases,
  * generate the various metric units of measure and add
  * them to this physical quantity.
  *
  * Names and Aliases are created by replacing identifiers in the respective
  * patterns.  The current allowed replacement identifiers are:
  *   %p = the abbreviated SI prefix, like 'M' for 'megameter' or 'k' for 'kilogram'
  *   %P = the full SI prefix, like 'mega' for 'megameter' or 'kilo' for 'kilogram'
  *   %U = uppercase version of %P
  *
  * So for instance, in order to generate 'kg', 'mg', and 'g' names for SI units, the
  * appropriate pattern would be '%pg'.  Similarly, to generate 'kilogram', 'milligram',
  * and 'gram' aliases, the pattern would be '%Pgram'.
  *
  * The $siUnit given in the 1st parameter must be some SI unit in the series of units
  * to be generated by this method.  This value is necessary to establish a conversion
  * factor between this continuum of SI units and the Physical Quantity's native unit.
  *
  * The second parameter provides a scaling factor between the given SI unit in the first parameter
  * and the base unit of the SI continuum (ie, 'grams', 'meters', 'seconds', etc).  For instance,
  * if a Kilogram unit of measure was passed for the 1st parameter, it would be necessary to
  * then pass 1e-3 in the 2nd parameter to indicate that a gram is 1/1000 of the given unit.
  *
  * @param  UnitOfMeasure $siUnit             A unit in this physical quantity that is an SI unit of measure
  * @param  integer       $toBaseSiUnitFactor The power-of-ten factor that converts the given SI unit into the not-prefixed SI base unit (ie 1e-3 for kilograms)
  * @param  string        $namePattern        The pattern to apply to the base unit's name to generate a new SI unit name
  * @param  array         $aliasPatterns      The collection of alias patterns to use in generating a new SI unit's aliases
  */
 protected static function addMissingSIPrefixedUnits(UnitOfMeasure $siUnit, $toBaseSiUnitFactor, $namePattern, array $aliasPatterns = [])
 {
     /**
      * The standard set of SI prefixes
      */
     $siPrefixes = [['abbr_prefix' => 'Y', 'long_prefix' => 'yotta', 'factor' => 1.0E+24], ['abbr_prefix' => 'Z', 'long_prefix' => 'zetta', 'factor' => 1.0E+21], ['abbr_prefix' => 'E', 'long_prefix' => 'exa', 'factor' => 1.0E+18], ['abbr_prefix' => 'P', 'long_prefix' => 'peta', 'factor' => 1000000000000000.0], ['abbr_prefix' => 'T', 'long_prefix' => 'tera', 'factor' => 1000000000000.0], ['abbr_prefix' => 'G', 'long_prefix' => 'giga', 'factor' => 1000000000.0], ['abbr_prefix' => 'M', 'long_prefix' => 'mega', 'factor' => 1000000.0], ['abbr_prefix' => 'k', 'long_prefix' => 'kilo', 'factor' => 1000.0], ['abbr_prefix' => 'h', 'long_prefix' => 'hecto', 'factor' => 100.0], ['abbr_prefix' => 'da', 'long_prefix' => 'deca', 'factor' => 10.0], ['abbr_prefix' => '', 'long_prefix' => '', 'factor' => 1], ['abbr_prefix' => 'd', 'long_prefix' => 'deci', 'factor' => 0.1], ['abbr_prefix' => 'c', 'long_prefix' => 'centi', 'factor' => 0.01], ['abbr_prefix' => 'm', 'long_prefix' => 'milli', 'factor' => 0.001], ['abbr_prefix' => 'µ', 'long_prefix' => 'micro', 'factor' => 1.0E-6], ['abbr_prefix' => 'n', 'long_prefix' => 'nano', 'factor' => 1.0E-9], ['abbr_prefix' => 'p', 'long_prefix' => 'pico', 'factor' => 1.0E-12], ['abbr_prefix' => 'f', 'long_prefix' => 'femto', 'factor' => 1.0E-15], ['abbr_prefix' => 'a', 'long_prefix' => 'atto', 'factor' => 1.0E-18], ['abbr_prefix' => 'z', 'long_prefix' => 'zepto', 'factor' => 9.999999999999999E-22], ['abbr_prefix' => 'y', 'long_prefix' => 'yocto', 'factor' => 9.999999999999999E-25]];
     // Determine the conversion factor from the no-prefix SI unit to the physical quantity's native unit
     $noPrefixToNativeUnitFactor = $siUnit->convertValueToNativeUnitOfMeasure(1) * $toBaseSiUnitFactor;
     // For each of the standard SI prefixes, attempt to register a new unit of measure
     foreach ($siPrefixes as $prefixDefinition) {
         // Build a function for resolving a pattern into a unit name
         $parsePattern = function ($pattern) use($prefixDefinition) {
             return strtr($pattern, ['%p' => $prefixDefinition['abbr_prefix'], '%P' => $prefixDefinition['long_prefix'], '%U' => strtoupper($prefixDefinition['long_prefix'])]);
         };
         // Generate the base name of the new unit
         $name = $parsePattern($namePattern);
         // Determine the factor that converts the new unit into the physical quantity's
         //   native unit of measure.
         $toNativeUnitFactor = $noPrefixToNativeUnitFactor * $prefixDefinition['factor'];
         // Instantiate the new unit of measure
         $newUnit = UnitOfMeasure::linearUnitFactory($name, $toNativeUnitFactor);
         // Generate the aliases of the new unit
         foreach ($aliasPatterns as $aliasPattern) {
             $newUnitAlias = $parsePattern($aliasPattern);
             $newUnit->addAlias($newUnitAlias);
         }
         // If the unit doesn't conflict with any of the already-existing units, register it
         if (!static::unitNameOrAliasesAlreadyRegistered($newUnit)) {
             static::addUnit($newUnit);
         }
     }
 }