{"id":29769012,"url":"https://github.com/featurevisor/featurevisor-php","last_synced_at":"2026-01-20T16:37:52.553Z","repository":{"id":306669975,"uuid":"1026913998","full_name":"featurevisor/featurevisor-php","owner":"featurevisor","description":"PHP SDK for Featurevisor","archived":false,"fork":false,"pushed_at":"2025-08-28T20:20:09.000Z","size":85,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-29T02:00:46.461Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/featurevisor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-26T22:23:00.000Z","updated_at":"2025-08-28T20:20:13.000Z","dependencies_parsed_at":"2025-07-27T01:23:21.056Z","dependency_job_id":"a47a3fb2-8490-4b1e-aeb1-b36cb0ec5e2c","html_url":"https://github.com/featurevisor/featurevisor-php","commit_stats":null,"previous_names":["featurevisor/featurevisor-php"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/featurevisor/featurevisor-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/featurevisor","download_url":"https://codeload.github.com/featurevisor/featurevisor-php/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-php/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272631574,"owners_count":24967104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-29T02:00:10.610Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2025-07-27T03:36:31.753Z","updated_at":"2026-01-20T16:37:52.546Z","avatar_url":"https://github.com/featurevisor.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Featurevisor PHP SDK \u003c!-- omit in toc --\u003e\n\nThis is a port of Featurevisor [Javascript SDK](https://featurevisor.com/docs/sdks/javascript/) v2.x to PHP, providing a way to evaluate feature flags, variations, and variables in your PHP applications.\n\nThis SDK is compatible with [Featurevisor](https://featurevisor.com/) v2.0 projects and above.\n\n## Table of contents \u003c!-- omit in toc --\u003e\n\n- [Installation](#installation)\n- [Initialization](#initialization)\n- [Evaluation types](#evaluation-types)\n- [Context](#context)\n  - [Setting initial context](#setting-initial-context)\n  - [Setting after initialization](#setting-after-initialization)\n  - [Replacing existing context](#replacing-existing-context)\n  - [Manually passing context](#manually-passing-context)\n- [Check if enabled](#check-if-enabled)\n- [Getting variation](#getting-variation)\n- [Getting variables](#getting-variables)\n  - [Type specific methods](#type-specific-methods)\n- [Getting all evaluations](#getting-all-evaluations)\n- [Sticky](#sticky)\n  - [Initialize with sticky](#initialize-with-sticky)\n  - [Set sticky afterwards](#set-sticky-afterwards)\n- [Setting datafile](#setting-datafile)\n  - [Updating datafile](#updating-datafile)\n  - [Interval-based update](#interval-based-update)\n- [Logging](#logging)\n  - [Customizing levels](#customizing-levels)\n  - [Handler](#handler)\n- [Events](#events)\n  - [`datafile_set`](#datafile_set)\n  - [`context_set`](#context_set)\n  - [`sticky_set`](#sticky_set)\n- [Evaluation details](#evaluation-details)\n- [Hooks](#hooks)\n  - [Defining a hook](#defining-a-hook)\n  - [Registering hooks](#registering-hooks)\n- [Child instance](#child-instance)\n- [Close](#close)\n- [CLI usage](#cli-usage)\n  - [Test](#test)\n  - [Benchmark](#benchmark)\n  - [Assess distribution](#assess-distribution)\n- [Development of this package](#development-of-this-package)\n  - [Setting up](#setting-up)\n  - [Running tests](#running-tests)\n  - [Releasing](#releasing)\n- [License](#license)\n\n\u003c!-- FEATUREVISOR_DOCS_BEGIN --\u003e\n\n## Installation\n\nIn your PHP application, install the SDK using [Composer](https://getcomposer.org/):\n\n```\n$ composer require featurevisor/featurevisor-php\n```\n\n## Initialization\n\nThe SDK can be initialized by passing [datafile](https://featurevisor.com/docs/building-datafiles/) content directly:\n\n```php\n\u003c?php\n\nuse Featurevisor\\Featurevisor;\n\n$datafileUrl = \"https://cdn.yoursite.com/datafile.json\";\n\n$datafileContent = file_get_contents($datafileUrl);\n$datafileContent = json_decode($datafileContent, true);\n\n$f = Featurevisor::createInstance([\n  \"datafile\" =\u003e $datafileContent\n]);\n```\n\n## Evaluation types\n\nWe can evaluate 3 types of values against a particular [feature](https://featurevisor.com/docs/features/):\n\n- [**Flag**](#check-if-enabled) (`boolean`): whether the feature is enabled or not\n- [**Variation**](#getting-variation) (`string`): the variation of the feature (if any)\n- [**Variables**](#getting-variables): variable values of the feature (if any)\n\nThese evaluations are run against the provided context.\n\n## Context\n\nContexts are [attribute](https://featurevisor.com/docs/attributes) values that we pass to SDK for evaluating [features](https://featurevisor.com/docs/features) against.\n\nThink of the conditions that you define in your [segments](https://featurevisor.com/docs/segments/), which are used in your feature's [rules](https://featurevisor.com/docs/features/#rules).\n\nThey are plain objects:\n\n```php\n$context = [\n  \"userId\" =\u003e \"123\",\n  \"country\" =\u003e \"nl\",\n  // ...other attributes\n];\n```\n\nContext can be passed to SDK instance in various different ways, depending on your needs:\n\n### Setting initial context\n\nYou can set context at the time of initialization:\n\n```php\nuse Featurevisor\\Featurevisor;\n\n$f = Featurevisor::createInstance([\n  \"context\" =\u003e [\n    \"deviceId\" =\u003e \"123\",\n    \"country\" =\u003e \"nl\",\n  ],\n]);\n```\n\nThis is useful for values that don't change too frequently and available at the time of application startup.\n\n### Setting after initialization\n\nYou can also set more context after the SDK has been initialized:\n\n```php\n$f-\u003esetContext([\n  \"userId\" =\u003e \"123\",\n  \"country\" =\u003e \"nl\",\n]);\n```\n\nThis will merge the new context with the existing one (if already set).\n\n### Replacing existing context\n\nIf you wish to fully replace the existing context, you can pass `true` in second argument:\n\n```php\n$f-\u003esetContext(\n  [\n    \"deviceId\" =\u003e \"123\",\n    \"userId\" =\u003e \"234\",\n    \"country\" =\u003e \"nl\",\n    \"browser\" =\u003e \"chrome\",\n  ],\n  true // replace existing context\n);\n```\n\n### Manually passing context\n\nYou can optionally pass additional context manually for each and every evaluation separately, without needing to set it to the SDK instance affecting all evaluations:\n\n```php\n$context = [\n  \"userId\" =\u003e \"123\",\n  \"country\" =\u003e \"nl\",\n];\n\n$isEnabled = $f-\u003eisEnabled('my_feature', $context);\n$variation = $f-\u003egetVariation('my_feature', $context);\n$variableValue = $f-\u003egetVariable('my_feature', 'my_variable', $context);\n```\n\nWhen manually passing context, it will merge with existing context set to the SDK instance before evaluating the specific value.\n\nFurther details for each evaluation types are described below.\n\n## Check if enabled\n\nOnce the SDK is initialized, you can check if a feature is enabled or not:\n\n```php\n$featureKey = 'my_feature';\n\n$isEnabled = $f-\u003eisEnabled($featureKey);\n\nif ($isEnabled) {\n  // do something\n}\n```\n\nYou can also pass additional context per evaluation:\n\n```php\n$isEnabled = $f-\u003eisEnabled($featureKey, [\n  // ...additional context\n]);\n```\n\n## Getting variation\n\nIf your feature has any [variations](https://featurevisor.com/docs/features/#variations) defined, you can evaluate them as follows:\n\n```php\n$featureKey = 'my_feature';\n\n$variation = $f-\u003egetVariation($featureKey);\n\nif ($variation === \"treatment\") {\n  // do something for treatment variation\n} else {\n  // handle default/control variation\n}\n```\n\nAdditional context per evaluation can also be passed:\n\n```php\n$variation = $f-\u003egetVariation($featureKey, [\n  // ...additional context\n]);\n```\n\n## Getting variables\n\nYour features may also include [variables](https://featurevisor.com/docs/features/#variables), which can be evaluated as follows:\n\n```php\n$variableKey = 'bgColor';\n\n$bgColorValue = $f-\u003egetVariable($featureKey, $variableKey);\n```\n\nAdditional context per evaluation can also be passed:\n\n```php\n$bgColorValue = $f-\u003egetVariable($featureKey, $variableKey, [\n  // ...additional context\n]);\n```\n\n### Type specific methods\n\nNext to generic `getVariable()` methods, there are also type specific methods available for convenience:\n\n```php\n$f-\u003egetVariableBoolean($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableString($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableInteger($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableDouble($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableArray($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableObject($featureKey, $variableKey, $context = []);\n$f-\u003egetVariableJSON($featureKey, $variableKey, $context = []);\n```\n\n## Getting all evaluations\n\nYou can get evaluations of all features available in the SDK instance:\n\n```php\n$allEvaluations = $f-\u003egetAllEvaluations($context = []);\n\nprint_r($allEvaluations);\n// [\n//   myFeature: [\n//     enabled: true,\n//     variation: \"control\",\n//     variables: [\n//       myVariableKey: \"myVariableValue\",\n//     ],\n//   ],\n//\n//   anotherFeature: [\n//     enabled: true,\n//     variation: \"treatment\",\n//   ]\n// ]\n```\n\nThis is handy especially when you want to pass all evaluations from a backend application to the frontend.\n\n## Sticky\n\nFor the lifecycle of the SDK instance in your application, you can set some features with sticky values, meaning that they will not be evaluated against the fetched [datafile](https://featurevisor.com/docs/building-datafiles/):\n\n### Initialize with sticky\n\n```php\nuse Featurevisor\\Featurevisor;\n\n$f = Featurevisor::createInstance([\n  \"sticky\" =\u003e [\n    \"myFeatureKey\" =\u003e [\n      \"enabled\" =\u003e true,\n\n      // optional\n      \"variation\" =\u003e 'treatment',\n      \"variables\" =\u003e [\n        \"myVariableKey\" =\u003e 'myVariableValue',\n      ],\n    ],\n\n    \"anotherFeatureKey\" =\u003e [\n      \"enabled\" =\u003e false,\n    ],\n  ],\n]);\n```\n\nOnce initialized with sticky features, the SDK will look for values there first before evaluating the targeting conditions and going through the bucketing process.\n\n### Set sticky afterwards\n\nYou can also set sticky features after the SDK is initialized:\n\n```php\n$f-\u003esetSticky(\n  [\n    \"myFeatureKey\" =\u003e [\n      \"enabled\" =\u003e true,\n      \"variation\" =\u003e 'treatment',\n      \"variables\" =\u003e [\n        \"myVariableKey\" =\u003e 'myVariableValue',\n      ],\n    ],\n    \"anotherFeatureKey\" =\u003e [\n      \"enabled\" =\u003e false,\n    ],\n  ],\n\n  // replace existing sticky features (false by default)\n  true\n]);\n```\n\n## Setting datafile\n\nYou may also initialize the SDK without passing `datafile`, and set it later on:\n\n```php\n$f-\u003esetDatafile($datafileContent);\n```\n\n### Updating datafile\n\nYou can set the datafile as many times as you want in your application, which will result in emitting a [`datafile_set`](#datafile_set) event that you can listen and react to accordingly.\n\nThe triggers for setting the datafile again can be:\n\n- periodic updates based on an interval (like every 5 minutes), or\n- reacting to:\n  - a specific event in your application (like a user action), or\n  - an event served via websocket or server-sent events (SSE)\n\n### Interval-based update\n\nHere's an example of using interval-based update:\n\n@TODO\n\n## Logging\n\nBy default, Featurevisor SDKs will print out logs to the console for `info` level and above.\nFeaturevisor PHP-SDK by default uses [PSR-3 standard](https://www.php-fig.org/psr/psr-3/) simple implementation.\nYou can also choose from many mature implementations like e.g. [Monolog](https://github.com/Seldaek/monolog)\n\n### Customizing levels\n\nIf you choose `debug` level to make the logs more verbose, you can set it at the time of SDK initialization.\n\nSetting `debug` level will print out all logs, including `info`, `warning`, and `error` levels.\n\n```php\nuse Featurevisor\\Featurevisor;\nuse Featurevisor\\Logger;\n\n$f = Featurevisor::createInstance([\n  \"logger\" =\u003e Logger::create([\n    \"level\" =\u003e \"debug\",\n  ]),\n]);\n```\n\nAlternatively, you can also set `logLevel` directly:\n\n```php\n$f = Featurevisor::createInstance([\n  \"logLevel\" =\u003e \"debug\",\n]);\n```\n\nYou can also set log level from SDK instance afterwards:\n\n```php\n$f-\u003esetLogLevel(\"debug\");\n```\n\n### Handler\n\nYou can also pass your own log handler, if you do not wish to print the logs to the console:\n\n```php\nuse Featurevisor\\Featurevisor;\nuse Featurevisor\\Logger;\n\n$f = Featurevisor::createInstance([\n  \"logger\" =\u003e Logger::create([\n    \"level\" =\u003e \"info\",\n    \"handler\" =\u003e function ($level, $message, $details) {\n      // do something with the log\n    },\n  ]),\n]);\n```\n\nFurther log levels like `info` and `debug` will help you understand how the feature variations and variables are evaluated in the runtime against given context.\n\n## Events\n\nFeaturevisor SDK implements a simple event emitter that allows you to listen to events that happen in the runtime.\n\nYou can listen to these events that can occur at various stages in your application:\n\n@TODO: verify these events\n\n### `datafile_set`\n\n```php\n$unsubscribe = $f-\u003eon('datafile_set', function ($event) {\n  $revision = $event['revision']; // new revision\n  $previousRevision = $event['previousRevision'];\n  $revisionChanged = $event['revisionChanged']; // true if revision has changed\n\n  // list of feature keys that have new updates,\n  // and you should re-evaluate them\n  $features = $event['features'];\n\n  // handle here\n});\n\n// stop listening to the event\n$unsubscribe();\n```\n\nThe `features` array will contain keys of features that have either been:\n\n- added, or\n- updated, or\n- removed\n\ncompared to the previous datafile content that existed in the SDK instance.\n\n### `context_set`\n\n```php\n$unsubscribe = $f-\u003eon('context_set', function ($event) {\n  $replaced = $event['replaced']; // true if context was replaced\n  $context = $event['context']; // the new context\n\n  echo \"Context set\";\n});\n```\n\n### `sticky_set`\n\n```php\n$unsubscribe = $f-\u003eon('sticky_set', function ($event) {\n  $replaced = $event['replaced']; // true if sticky features got replaced\n  $features = $event['features']; // list of all affected feature keys\n\n  echo \"Sticky features set\";\n});\n```\n\n## Evaluation details\n\nBesides logging with debug level enabled, you can also get more details about how the feature variations and variables are evaluated in the runtime against given context:\n\n```php\n// flag\n$evaluation = $f-\u003eevaluateFlag($featureKey, $context = []);\n\n// variation\n$evaluation = $f-\u003eevaluateVariation($featureKey, $context = []);\n\n// variable\n$evaluation = $f-\u003eevaluateVariable($featureKey, $variableKey, $context = []);\n```\n\nThe returned object will always contain the following properties:\n\n- `featureKey`: the feature key\n- `reason`: the reason how the value was evaluated\n\nAnd optionally these properties depending on whether you are evaluating a feature variation or a variable:\n\n- `bucketValue`: the bucket value between 0 and 100,000\n- `ruleKey`: the rule key\n- `error`: the error object\n- `enabled`: if feature itself is enabled or not\n- `variation`: the variation object\n- `variationValue`: the variation value\n- `variableKey`: the variable key\n- `variableValue`: the variable value\n- `variableSchema`: the variable schema\n\n## Hooks\n\nHooks allow you to intercept the evaluation process and customize it further as per your needs.\n\n### Defining a hook\n\nA hook is a simple object with a unique required `name` and optional functions:\n\n```php\n$myCustomHook = [\n  // only required property\n  'name' =\u003e 'my-custom-hook',\n\n  // rest of the properties below are all optional per hook\n\n  // before evaluation\n  'before' =\u003e function (options) {\n    $type = $options['type']; // `feature` | `variation` | `variable`\n    $featureKey = $options['featureKey'];\n    $variableKey = $options['variableKey']; // if type is `variable`\n    $context = $options['context'];\n\n    // update context before evaluation\n    $options['context'] = array_merge($options['context'], [\n      'someAdditionalAttribute' =\u003e 'value',\n    ]);\n\n    return $options;\n  },\n\n  // after evaluation\n  'after' =\u003e function ($evaluation, $options) {\n    $reason = $evaluation['reason']; // `error` | `feature_not_found` | `variable_not_found` | ...\n\n    if ($reason === \"error\") {\n      // log error\n\n      return;\n    }\n  },\n\n  // configure bucket key\n  'bucketKey' =\u003e function ($options) {\n    $featureKey = $options['featureKey'];\n    $context = $options['context'];\n    $bucketBy = $options['bucketBy'];\n    $bucketKey = $options['bucketKey']; // default bucket key\n\n    // return custom bucket key\n    return $bucketKey;\n  },\n\n  // configure bucket value (between 0 and 100,000)\n  'bucketValue' =\u003e function ($options) {\n    $featureKey = $options['featureKey'];\n    $context = $options['context'];\n    $bucketKey = $options['bucketKey'];\n    $bucketValue = $options['bucketValue']; // default bucket value\n\n    // return custom bucket value\n    return $bucketValue;\n  },\n];\n```\n\n### Registering hooks\n\nYou can register hooks at the time of SDK initialization:\n\n```php\nuse Featurevisor\\Featurevisor;\n\n$f = Featurevisor::createInstance([\n  'hooks' =\u003e [\n    $myCustomHook\n  ],\n]);\n```\n\nOr after initialization:\n\n```php\n$removeHook = $f-\u003eaddHook($myCustomHook);\n\n// $removeHook()\n```\n\n## Child instance\n\nWhen dealing with purely client-side applications, it is understandable that there is only one user involved, like in browser or mobile applications.\n\nBut when using Featurevisor SDK in server-side applications, where a single server instance can handle multiple user requests simultaneously, it is important to isolate the context for each request.\n\nThat's where child instances come in handy:\n\n```php\n$childF = $f-\u003espawn([\n  // user or request specific context\n  'userId' =\u003e '123',\n]);\n```\n\nNow you can pass the child instance where your individual request is being handled, and you can continue to evaluate features targeting that specific user alone:\n\n```php\n$isEnabled = $childF-\u003eisEnabled('my_feature');\n$variation = $childF-\u003egetVariation('my_feature');\n$variableValue = $childF-\u003egetVariable('my_feature', 'my_variable');\n```\n\nSimilar to parent SDK, child instances also support several additional methods:\n\n- `setContext`\n- `setSticky`\n- `isEnabled`\n- `getVariation`\n- `getVariable`\n- `getVariableBoolean`\n- `getVariableString`\n- `getVariableInteger`\n- `getVariableDouble`\n- `getVariableArray`\n- `getVariableObject`\n- `getVariableJSON`\n- `getAllEvaluations`\n- `on`\n- `close`\n\n## Close\n\nBoth primary and child instances support a `.close()` method, that removes forgotten event listeners (via `on` method) and cleans up any potential memory leaks.\n\n```php\n$f-\u003eclose();\n```\n\n## CLI usage\n\nThis package also provides a CLI tool for running your Featurevisor project's test specs and benchmarking against this PHP SDK:\n\n### Test\n\nLearn more about testing [here](https://featurevisor.com/docs/testing/).\n\n```\n$ vendor/bin/featurevisor test --projectDirectoryPath=\"/absolute/path/to/your/featurevisor/project\"\n```\n\nAdditional options that are available:\n\n```\n$ vendor/bin/featurevisor test \\\n    --projectDirectoryPath=\"/absolute/path/to/your/featurevisor/project\" \\\n    --quiet|verbose \\\n    --onlyFailures \\\n    --keyPattern=\"myFeatureKey\" \\\n    --assertionPattern=\"#1\"\n```\n\n### Benchmark\n\nLearn more about benchmarking [here](https://featurevisor.com/docs/cli/#benchmarking).\n\n```\n$ vendor/bin/featurevisor benchmark \\\n    --projectDirectoryPath=\"/absolute/path/to/your/featurevisor/project\" \\\n    --environment=\"production\" \\\n    --feature=\"myFeatureKey\" \\\n    --context='{\"country\": \"nl\"}' \\\n    --n=1000\n```\n\n### Assess distribution\n\nLearn more about assessing distribution [here](https://featurevisor.com/docs/cli/#assess-distribution).\n\n```\n$ vendor/bin/featurevisor assess-distribution \\\n    --projectDirectoryPath=\"/absolute/path/to/your/featurevisor/project\" \\\n    --environment=production \\\n    --feature=foo \\\n    --variation \\\n    --context='{\"country\": \"nl\"}' \\\n    --populateUuid=userId \\\n    --populateUuid=deviceId \\\n    --n=1000\n```\n\n\u003c!-- FEATUREVISOR_DOCS_END --\u003e\n\n## Development of this package\n\n### Setting up\n\nClone the repository, and install the dependencies using [Composer](https://getcomposer.org/):\n\n```\n$ composer install\n```\n\n### Running tests\n\n```\n$ composer test\n```\n\n### Releasing\n\n- Manually create a new release on [GitHub](https://github.com/featurevisor/featurevisor-php/releases)\n- Tag it with a prefix of `v`, like `v1.0.0`\n- GitHub Actions is set up to automatically notify [Packagist](https://packagist.org/packages/featurevisor/featurevisor-php) about the new release\n\n## License\n\nMIT © [Fahad Heylaal](https://fahad19.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-php/lists"}