{"id":16225756,"url":"https://github.com/macfja/phpkvo","last_synced_at":"2025-10-06T20:12:54.718Z","repository":{"id":62521317,"uuid":"52178460","full_name":"MacFJA/PhpKVO","owner":"MacFJA","description":"KVO (Key Value Observing) design pattern in PHP.","archived":false,"fork":false,"pushed_at":"2016-02-20T22:21:23.000Z","size":19,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-22T15:40:02.143Z","etag":null,"topics":["design-pattern","kvo"],"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/MacFJA.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":"2016-02-20T22:20:49.000Z","updated_at":"2017-11-16T15:51:09.000Z","dependencies_parsed_at":"2022-11-02T10:31:15.306Z","dependency_job_id":null,"html_url":"https://github.com/MacFJA/PhpKVO","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/MacFJA/PhpKVO","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacFJA%2FPhpKVO","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacFJA%2FPhpKVO/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacFJA%2FPhpKVO/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacFJA%2FPhpKVO/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MacFJA","download_url":"https://codeload.github.com/MacFJA/PhpKVO/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacFJA%2FPhpKVO/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278671792,"owners_count":26025756,"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-10-06T02:00:05.630Z","response_time":65,"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":["design-pattern","kvo"],"created_at":"2024-10-10T12:46:13.176Z","updated_at":"2025-10-06T20:12:54.685Z","avatar_url":"https://github.com/MacFJA.png","language":"PHP","readme":"# PhpKVO\n\n### [What is KVO](#what) \u0026nbsp; [Installation](#installation) \u0026nbsp; [Usage](#usage) \u0026nbsp; [API](#api)\n\n\n## What is KVO ?\u003ca id=\"what\"\u003e\u003c/a\u003e\n\nKVO (_Key Value Observing_) is a design pattern which allows an object to get notified about changes.  \nIt allow you keep your object synchronized each other without creating a hard link thanks to Subject/Observer design pattern.  \nKVC (_Key Value Coding_) and KVO (_Key Value Observing_) are heavily used in Cocoa Framework (Objective-C)\n\n## Installation\u003ca id=\"installation\"\u003e\u003c/a\u003e\n\nThe simplest way to install the library is to use [Composer](http://getcomposer.org/):\n\n```bash\ncomposer require macfja/php-kvo\n```\n\n## Usage\u003ca id=\"usage\"\u003e\u003c/a\u003e\n\n```php\nclass Downloader extends AbstractObservable\n{\n  protected $progress;\n  public function getProgress()\n  {\n    return $this-\u003eprogress;\n  }\n  protected function receiveCallback($newProgress)\n  {\n    $this-\u003esetValueForKey('progress', $newProgress);\n    // ... do something with the data\n  }\n  public function download()\n  {\n    // ... start the download\n  }\n}\n\nclass ProgressDisplay implements Listener\n{\n  public function observeValueForKeyPath($keyPath, $object, $change, \u0026$context)\n  {\n    if ($keyPath == 'progress') {\n      echo sprintf('Download in progress (%d%%)%s', $change[Observer::CHANGE_NEW], PHP_EOL);\n    }\n  }\n}\n\n$downloader = new Downloader();\n$progress = new ProgressDisplay();\n$downloader-\u003eaddObserverForKey($progress, 'progress', Observer::OPTION_NEW|Observer::OPTION_INITIAL);\n$downloader-\u003edownload()\n```\n\n---\n\nA complete examples can be found in the directory [examples](examples).\n\n## API\u003ca id=\"api\"\u003e\u003c/a\u003e\n\n### API of `Observable` interface\u003ca id=\"api_observable\"\u003e\u003c/a\u003e\n\nImplemented in `AbstractObservable`, `Proxy`.  \nA trait for quick implementation is available: `ObservableTrait`\n\n#### API of `Observable::addObserverForKey` method\n\nThis method allow you to subscribe to key value changes notification.\n\n| Type       | Variable    | Description |\n|------------|-------------|-------------|\n| [`Listener`](#api_listener) | `$listener` | The object that subscribe to the changes notification. |\n|string      | `$key`      | The key to listen. |\n|int\\|`0`         | `$options` _optional_ | The list of options. (More information below) |\n|mixed\\|`null` | `\u0026$context` _optional_ | The context: data to send with the notification. This value passed by reference. |\n\n#### API, The `Observable::addObserverForKey` options list.\n\n- **`Observer::OPTION_NEW`**, Indicates that the change array should provide the new attribute value, if applicable.\n\n- **`Observer::OPTION_OLD`**, Indicates that the change array should contain the old attribute value, if applicable.\n\n- **`Observer::OPTION_INITIAL`**, If specified, a notification should be sent to the observer immediately, before the observer registration method even returns.\n\n  The change array in the notification will always contain an `Observer::CHANGE_NEW` entry if `Observer::OPTION_NEW` is also specified but will never contain an `Observer::CHANGE_OLD` or `Observer::CHANGE_REQUESTED` entry.  \n  (In an initial notification the current value of the observed property may be old, but it's new to the observer.)\n\n- **`Observer::OPTION_PRIOR`**, Whether separate notifications should be sent to the observer before and after each change, instead of a single notification after the change.\n\n  The change array in a notification sent before a change always contains an `Observer::CHANGE_PRIOR` entry whose value is `true`, but never contains an `Observer::CHANGE_NEW` entry. When this option is specified the change array in a notification sent after a change contains the same entries that it would contain if this option were not specified. You can use this option when the observer's own key-value observing-compliance requires it to invoke the `willChangeValueForKey` method for one of its own properties, and the value of that property depends on the value of the observed object's property.\n\n#### API of `Observable::willChangeValueForKey` method\n\nThis method trigger a notification for all [`Listener`](#api_listener) that registered for a key with the option `Observer::OPTION_PRIOR`.  \nThis method should be call **before** the key value change.\n\n| Type        | Variable          | Description |\n|-------------|-------------------|-------------|\n| string      | `$key`            | The key that is changed. |\n| string      | `$source`         | The source/type of change. (More information below). |\n| null\\|mixed | `$oldValue` _optional_ | The current value of the key. |\n| null\\|mixed | `$requestedValue` _optional_ | The requested new value of the key. |\n\n#### API of `Observable::didChangeValueForKey` method\n\nThis method trigger a notification for all [`Listener`](#api_listener) that registered for a key without the option `Observer::OPTION_PRIOR`.  \nThis method should be call **after** the key value change.\n\n| Type          | Variable          | Description |\n|---------------|-------------------|-------------|\n| string        | `$key`            | The key that is changed. |\n| string        | `$source`         | The source/type of change. (More information below). |\n| mixed\\|`null` | `$oldValue` _optional_ | The value of the key before the change. |\n| mixed\\|`null` | `$requestedValue` _optional_ | The requested new value of the key. |\n| mixed\\|`null` | `$newValue` _optional_ | The current value of the key. |\n\n#### API of `Observer::setValueForKey` method\n\nThis method change the value of a key and handle the call of methods `Observable::willChangeValueForKey` and `Observable::didChangeValueForKey`.\n\n| Type   | Variable | Description        |\n|--------|----------|--------------------|\n| string | `$key`   | The key to change. |\n| mixed  | `$value` | The new value.     |\n\n#### API, the `Observable::willChangeValueForKey` and `Observable::didChangeValueForKey` source value\n\n- **`Observer::SOURCE_SETTER`**, If the value of the key was changed from a _setter_ method. (Used by [`Proxy`](#api_proxy) class)\n- **`Observer::SOURCE_PROPERTY`**, If the value of the key was changed from a direct property change (public class property). (Used by [`Proxy`](#api_proxy) class)\n- **`Observer::SOURCE_CUSTOM`**, If the value was change without a setter, or from a direct property access.\n\nNote: You can use your own source type, it's just a string.\n\nNote: **`Observer::SOURCE_INITIAL`**, If the [`Listener`](#api_listener) has the option `Observer::OPTION_INITIAL`, then when registered, this source is used\n\n### API of `Listener` interface\u003ca id=\"api_listener\"\u003e\u003c/a\u003e\n\n#### API of `Listener::observeValueForKeyPath` method\n\nThis method is call every time an observed key is modified.\n\n| Type   | Variable    | Description |\n|--------|-------------|-------------|\n| string | `$keyPath`  | The modified key. |\n| object | `$key`      | The modified object. |\n| array  | `$change`   | The changed data. (More information below) |\n| mixed  | `\u0026$context` | The changed context (provided on subscription). |\n\n#### API, The `Listener::observeValueForKeyPath` change array\n\n- **`Observer::CHANGE_NEW`**, If the `Observer::OPTION_NEW` was specified when the observer was registered, the value of this key is the new value for the attribute.\n\n- **`Observer::CHANGE_OLD`**, If the `Observer::OPTION_OLD` was specified when the observer was registered, the value of this key is the value before the attribute was changed.\n\n- **`Observer::CHANGE_PRIOR`**, If the option `Observer::OPTION_PRIOR` was specified when the observer was registered this notification is sent prior to a change.\n\n  The change array contains an `Observer::CHANGE_PRIOR` entry whose value is `true` if the nofication is before the change, or `false` if the notification is after.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacfja%2Fphpkvo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmacfja%2Fphpkvo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacfja%2Fphpkvo/lists"}