{"id":36978464,"url":"https://github.com/tonix-tuft/linked-hash-map","last_synced_at":"2026-01-13T22:47:57.642Z","repository":{"id":57071607,"uuid":"385739986","full_name":"tonix-tuft/linked-hash-map","owner":"tonix-tuft","description":"How I would implement a linked hash map in PHP if PHP wouldn't have associative arrays.","archived":false,"fork":false,"pushed_at":"2021-07-17T09:35:31.000Z","size":48,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-16T19:04:25.143Z","etag":null,"topics":["data-structure","data-structures","hash-map","hash-table","linked","linked-hash-map","map"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tonix-tuft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-13T21:31:09.000Z","updated_at":"2021-07-17T09:35:31.000Z","dependencies_parsed_at":"2022-08-24T14:54:29.092Z","dependency_job_id":null,"html_url":"https://github.com/tonix-tuft/linked-hash-map","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/tonix-tuft/linked-hash-map","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonix-tuft%2Flinked-hash-map","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonix-tuft%2Flinked-hash-map/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonix-tuft%2Flinked-hash-map/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonix-tuft%2Flinked-hash-map/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tonix-tuft","download_url":"https://codeload.github.com/tonix-tuft/linked-hash-map/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tonix-tuft%2Flinked-hash-map/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28403739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-structure","data-structures","hash-map","hash-table","linked","linked-hash-map","map"],"created_at":"2026-01-13T22:47:56.896Z","updated_at":"2026-01-13T22:47:57.637Z","avatar_url":"https://github.com/tonix-tuft.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# linked-hash-map\n\nHow I would implement a linked hash map in PHP if PHP wouldn't have associative arrays.\n\n## Installation\n\nUsing [Composer](https://getcomposer.org/):\n\n```\ncomposer require tonix-tuft/linked-hash-map\n```\n\n## Usage\n\nThis map implements the [ArrayAccess](https://www.php.net/manual/en/class.arrayaccess.php) interface as well as the [Iterator](https://www.php.net/manual/en/class.iterator.php) and [Countable](https://www.php.net/manual/en/class.countable.php) interfaces and therefore can be used as a built-in PHP array:\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map['abc'] = 'string (abc)';\n$map['abcdef'] = 'string (abcdef)';\n$map[123] = 'int (123)';\n\nvar_dump(count($map)); // 3\n\nforeach ($map as $key =\u003e $value) {\n  var_dump($key, $value);\n}\n```\n\n### Using any PHP data type for the key\n\nThis map allows using any PHP type for the key (i.e. even an array or an object can be used for the key):\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map[true] = 'bool (true)';\n$map[false] = 'bool (false)';\n$map[32441] = 'int (32441)';\n$map[-32441] = 'int (-32441)';\n$map[2147483647] = 'int (2147483647)';\n$map[-2147483648] = 'int (-2147483648)';\n$map[PHP_INT_MAX - 100] = 'int (PHP_INT_MAX - 100)';\n$map[PHP_INT_MIN] = 'int (PHP_INT_MIN)';\n$map[0.5] = 'float/double (0.5)';\n$map[-0.5] = 'float/double (-0.5)';\n$map[123891.73] = 'float/double (123891.73)';\n$map[-123891.73] = 'float/double (-123891.73)';\n$map[PHP_INT_MAX + 10] = 'float/double (PHP_INT_MAX + 10)';\n$map[PHP_INT_MIN - 10] = 'float/double (PHP_INT_MIN - 10)';\n$map['abc'] = 'string (abc)';\n$map[\"abcdef\"] = \"string (abcdef)\";\n$map['hfudsh873hu2ifl'] = \"string (hfudsh873hu2ifl)\";\n$map[\"The quick brown fox jumps over the lazy dog\"] =\n  'string (The quick brown fox jumps over the lazy dog)';\n$map[[1, 2, 3]] = 'array ([1, 2, 3])';\n$map[['a', 'b', 'c']] = \"array (['a', 'b', 'c'])\";\n$map[[1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]]] =\n  \"array ([1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]])\";\n\n$arrayKey = [\n  1,\n  'a',\n  false,\n  5,\n  true,\n  [1, 2, 3, ['f', 5, [new stdClass(), new stdClass()]]],\n  new ArrayIterator(),\n];\n$map[$arrayKey] =\n  \"array ([1, 'a', false, 5, true, [1, 2, 3, ['f', 5, [new stdClass(), new stdClass()]]], new ArrayIterator()])\";\n\n$stdClassObj = new stdClass();\n$map[$stdClassObj] = \"object (new stdClass())\";\n\n$arrayIterator = new ArrayIterator();\n$map[$arrayIterator] = \"object (new ArrayIterator())\";\n\nclass A {\n}\n$objA = new A();\n$map[$objA] = \"object (new A())\";\n\n$fp = fopen(__DIR__ . '/private_local_file', 'w');\n$map[$fp] = \"resource (fopen())\";\n\n$ch = curl_init();\n$map[$ch] = \"resource (curl_init())\";\n\n// All the values can be retrieved later using the corresponding key, e.g.:\nvar_dump($map[[1, 2, 3]]); // \"array ([1, 2, 3])\"\nvar_dump($map[$objA]); // \"object (new A())\"\nvar_dump($map[$ch]); // \"resource (curl_init())\"\n```\n\n### Differences and similarities between this map and built-in PHP arrays\n\nThe differences between this map and built-in PHP arrays as well as any similarities are the following:\n\n1. Any PHP data type can be used for the key (`bool`, `int`, `float/double`, `string`, `array`, `object`, `callable`, `iterable`, `resource`) when using this map.\n   This also means that for example a float/double `1.5` will be used for the key as-is, whereas in built-in PHP arrays `1.5` is [type-juggled](https://www.php.net/manual/en/language.types.type-juggling.php) to `1`:\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map[1.5] = 'A value for key 1.5';\nvar_dump($map[1.5]); // \"A value for key 1.5\"\nvar_dump($map[1]); // NULL\n\n$arr = [];\n$arr[1.5] = 'A value'; // [1 =\u003e \"A value\"];\nvar_dump($arr[1.5]); // \"A value\"\nvar_dump($arr[1]); // \"A value\"\n```\n\n2. This map allows prepending instead of appending when setting the `LinkedHashMap::INSERT_MODE_PREPEND` flag (using the `setInsertMode` method):\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map-\u003esetInsertMode(LinkedHashMap::INSERT_MODE_PREPEND); // Defaults to `LinkedHashMap::INSERT_MODE_APPEND`\n$map['a'] = 1;\n$map['b'] = 2;\n\nforeach ($map as $key =\u003e $value) {\n  var_dump($key, $value);\n}\n// 'b', 2\n// 'a', 1\n```\n\n3. This map also allows setting the loop order (iteration) order (using the `setLoopOrder` method), whether normal (`LinkedHashMap::LOOP_ORDER_NORMAL`, the default) or reversed (`LinkedHashMap::LOOP_ORDER_REVERSE`):\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n// Example 1:\n$map = new LinkedHashMap();\n$map-\u003esetLoopOrder(LinkedHashMap::LOOP_ORDER_REVERSE); // Defaults to `LinkedHashMap::LOOP_ORDER_NORMAL`\n$map['a'] = 1;\n$map['b'] = 2;\n\nforeach ($map as $key =\u003e $value) {\n  var_dump($key, $value);\n}\n// 'b', 2\n// 'a', 1\n\n// Example 2:\n$map = new LinkedHashMap();\n$map-\u003esetInsertMode(LinkedHashMap::INSERT_MODE_PREPEND); // Defaults to `LinkedHashMap::INSERT_MODE_APPEND`\n$map-\u003esetLoopOrder(LinkedHashMap::LOOP_ORDER_REVERSE); // Defaults to `LinkedHashMap::LOOP_ORDER_NORMAL`\n$map['a'] = 1;\n$map['b'] = 2;\n\nforeach ($map as $key =\u003e $value) {\n  var_dump($key, $value);\n}\n// 'a', 1\n// 'b', 2\n```\n\n4. Appending/prepending to the map works in the same way as with built-in PHP arrays (a positional index (an `int or integer string \u003e= 0`) is created or the highest positional index used so far is incremented internally).\n   Accessing an unknown index does not trigger/emit a notice (just returns `NULL`):\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map[] = 'Value for index 0';\n$map[] = 'Value for index 1';\n$map[1234] = 'Value for index 1234';\n$map[] = 'Value for index 1235';\nvar_dump($map[0]); // \"Value for index 0\"\nvar_dump($map[1]); // \"Value for index 1\"\nvar_dump($map[2]); // NULL (no E_NOTICE/E_USER_NOTICE)\nvar_dump($map[1234]); // \"Value for index 1234\"\nvar_dump($map[1235]); // \"Value for index 1235\"\n\n$arr = [];\n$arr[] = 'Value for index 0';\n$arr[] = 'Value for index 1';\n$arr[1234] = 'Value for index 1234';\n$arr[] = 'Value for index 1235';\nvar_dump($arr[0]); // \"Value for index 0\"\nvar_dump($arr[1]); // \"Value for index 1\"\nvar_dump($arr[2]); // NULL (emits E_NOTICE)\nvar_dump($arr[1234]); // \"Value for index 1234\"\nvar_dump($arr[1235]); // \"Value for index 1235\"\n```\n\n5. Because [ArrayAccess::offsetSet](https://www.php.net/manual/en/arrayaccess.offsetset.php) doesn't allow to differentiate between `NULL` and an append/prepend operation (`$map[] = 'A value'`), `NULL` cannot be used for the key. Using `NULL` for the key will be considered as an append/prepend operation. As built-in PHP arrays map `NULL` to an empty string `''`, this shouldn't be an issue:\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\n\n$map = new LinkedHashMap();\n$map[null] = 'Value for index 0';\n$map[null] = 'Value for index 1';\n$map[1234] = 'Value for index 1234';\n$map[null] = 'Value for index 1235';\nvar_dump($map[0]); // \"Value for index 0\"\nvar_dump($map[1]); // \"Value for index 1\"\nvar_dump($map[1234]); // \"Value for index 1234\"\nvar_dump($map[1235]); // \"Value for index 1235\"\nvar_dump($map[null]); // NULL\nvar_dump($map['']); // NULL\n\n$arr = [];\n$arr[null] = 'Value for index 0';\n$arr[null] = 'Value for index 1';\n$arr[1234] = 'Value for index 1234';\n$arr[null] = 'Value for index 1235';\nvar_dump($arr[0]); // NULL (emits E_NOTICE)\nvar_dump($arr[1]); // NULL (emits E_NOTICE)\nvar_dump($arr[1234]); // \"Value for index 1234\"\nvar_dump($arr[1235]); // NULL (emits E_NOTICE)\nvar_dump($arr[null]); // \"Value for index 1235\"\nvar_dump($arr['']); // \"Value for index 1235\"\n```\n\n### Using a custom hash code\n\nInternally, the map computes the hash for the given key in order to retrieve the corresponding value using the package [int-hash](https://packagist.org/packages/tonix-tuft/int-hash).\nIf the key is an instance of a class implementing the `LinkedHashMap\\HashCodeInterface` interface, its `hashCode` method will be called and the returned hash code (an integer) will be used instead:\n\n```php\n\u003c?php\n\nuse LinkedHashMap\\LinkedHashMap;\nuse LinkedHashMap\\HashCodeInterface;\n\nclass ClassWithCustomHashCode implements HashCodeInterface {\n  /**\n   * @var int\n   */\n  protected $propertyA;\n\n  /**\n   * @var int\n   */\n  protected $propertyB;\n\n  public function __construct() {\n    $this-\u003epropertyA = rand(0, 100000);\n    $this-\u003epropertyB = rand(0, 100000);\n  }\n\n  // ...\n\n  /**\n   * {@inheritdoc}\n   */\n  public function hashCode() {\n    // Compute the hash code somehow...\n    $prime = 31;\n    $hash = 1;\n    $hash = $prime * $hash + $this-\u003epropertyA;\n    $hash = $prime * $hash + $this-\u003epropertyB;\n    return $hash;\n  }\n}\n\n$map = new LinkedHashMap();\n\n$obj1 = new ClassWithCustomHashCode();\n$obj2 = new ClassWithCustomHashCode();\n\n$map[$obj1] = \"A value\";\n$map[$obj2] = \"Another value\";\n\nvar_dump($map[$obj1]); // \"A value\"\nvar_dump($map[$obj2]); // \"Another value\"\n```\n\n## License\n\nMIT © [Anton Bagdatyev (Tonix)](https://github.com/tonix-tuft)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonix-tuft%2Flinked-hash-map","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftonix-tuft%2Flinked-hash-map","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftonix-tuft%2Flinked-hash-map/lists"}