code: protected function getHierarchyKey($key, &$pathKey = null)
      {
          if (!$this->isHierarchyKey($key)) {
              return $key;
          }
  
          $key = $this->explodeKey($key);
  
          $keyString = '';
          // The comments below is for a $key = ["foo!tagHash", "bar!tagHash"]
          foreach ($key as $name) {
              // 1) $keyString = "foo!tagHash"
              // 2) $keyString = "foo!tagHash![foo_index]!bar!tagHash"
              $keyString .= $name;
              $pathKey = sha1('path'.AbstractCachePool::SEPARATOR_TAG.$keyString);
  
              if (isset($this->keyCache[$pathKey])) {
                  $index = $this->keyCache[$pathKey];
              } else {
                  $index                    = $this->getDirectValue($pathKey);
                  $this->keyCache[$pathKey] = $index;
              }
  
              // 1) $keyString = "foo!tagHash![foo_index]!"
              // 2) $keyString = "foo!tagHash![foo_index]!bar!tagHash![bar_index]!"
              $keyString .= AbstractCachePool::SEPARATOR_TAG.$index.AbstractCachePool::SEPARATOR_TAG;
          }
  
          // Assert: $pathKey = "path!foo!tagHash![foo_index]!bar!tagHash"
          // Assert: $keyString = "foo!tagHash![foo_index]!bar!tagHash![bar_index]!"
  
          // Make sure we do not get awfully long (>250 chars) keys
          return sha1($keyString);
      }
docs: Get a key to use with the hierarchy. If the key does not start with HierarchicalPoolInterface::SEPARATOR
  this will return an unalterered key. This function supports a tagged key. Ie "foo:bar".
  
  @param string $key      The original key
  @param string &$pathKey A cache key for the path. If this key is changed everything beyond that path is changed.
  
  @return string|array