{"id":33993558,"url":"https://github.com/subiabre/phpmetro","last_synced_at":"2025-12-13T07:24:57.768Z","repository":{"id":57060939,"uuid":"240975382","full_name":"subiabre/phpmetro","owner":"subiabre","description":"Streamlined sampling and analysis of results in PHP.","archived":false,"fork":false,"pushed_at":"2022-01-23T19:52:44.000Z","size":238,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-11T03:23:05.735Z","etag":null,"topics":["analysis","sampling","statistics","testing"],"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/subiabre.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":"2020-02-16T22:21:44.000Z","updated_at":"2022-01-23T19:43:48.000Z","dependencies_parsed_at":"2022-08-24T14:53:42.585Z","dependency_job_id":null,"html_url":"https://github.com/subiabre/phpmetro","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/subiabre/phpmetro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subiabre%2Fphpmetro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subiabre%2Fphpmetro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subiabre%2Fphpmetro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subiabre%2Fphpmetro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/subiabre","download_url":"https://codeload.github.com/subiabre/phpmetro/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subiabre%2Fphpmetro/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27701977,"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-12-13T02:00:09.769Z","response_time":147,"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":["analysis","sampling","statistics","testing"],"created_at":"2025-12-13T07:24:57.324Z","updated_at":"2025-12-13T07:24:57.755Z","avatar_url":"https://github.com/subiabre.png","language":"PHP","readme":"# PHPMetro\nStreamlined statistical sampling and analysis of results.\n\n![PHPMetro logo](https://user-images.githubusercontent.com/61125897/75801933-35e8d280-5d7c-11ea-9eab-8f788f97a0d9.png)\n\n[![License](https://poser.pugx.org/subiabre/phpmetro/license)](https://packagist.org/packages/subiabre/phpmetro)\n[![Latest Stable Version](https://poser.pugx.org/subiabre/phpmetro/version)](https://packagist.org/packages/subiabre/phpmetro)\n![CI](https://github.com/subiabre/phpmetro/workflows/CI/badge.svg?branch=master)\n[![codecov](https://codecov.io/gh/subiabre/phpmetro/branch/master/graph/badge.svg)](https://codecov.io/gh/subiabre/phpmetro)\n[![Latest Unstable Version](https://poser.pugx.org/subiabre/phpmetro/v/unstable)](//packagist.org/packages/subiabre/phpmetro)\n[![Total Downloads](https://poser.pugx.org/subiabre/phpmetro/downloads)](https://packagist.org/packages/subiabre/phpmetro)\n\nPHPMetro provides the foundation to perform sampling and analysis of data in a PHPUnit-like fashion, aiming to make it as easy as possible for PHP developers to compose analysis suites and get statistical results.\n\n1. [About](#About)\n2. [Requirements](#Requirements)\n3. [Installation](#Installation)\n4. [Configuration](#Configuration)\n5. [Usage (basic tutorial)](#Usage)\n6. [Support](#Support)\n\n---\n\n## About\nI created this package on winter 2019 because I was working on a project that required me to not only perform unit and functional tests of my code, but to also create and perform several statistical analyses of my code. PHPMetro was my response to that requirement.\n\n\u003e**WARNING**: Despite the origin of this project being that of a professional environment, it's not granted to be suitable for all production environments.\n\n## Requirements\n- PHP \u003e= 7.2*\n- [Composer](https://getcomposer.org)\n\n*Package should be compatible with older versions of PHP down to 5.x, but it's not granted.\n\n## Installation\nPHPMetro is distributed on [packagist](https://packagist.org/packages/subiabre/phpmetro).\n\n```console\n$ composer require --dev subiabre/phpmetro\n```\n\nOnce installed you'll get the phpmetro binary in your bin folder, by default **vendor/bin**. After installation you'll want to run `composer suggests subiabre/phpmetro` to see some more libraries you'll find useful when writing your analyses, as PHPMetro only contains a basic toolset for describing analysis cases with an specific workflow, and a runner to perform all our analyses based on a given configuration.\n\n## Configuration\nPHPMetro **needs** to be fed a `.xml` config file on run. This file will tell where to search for our Analysis classes and how to run them.\n\n### Getting the template configuration\nEasiest way is to copy to the root of your project the example config file at your vendor folder:\n\n```console\n$ cp vendor/subiabre/phpmetro/phpmetro.xml phpmetro.xml\n```\n\nThe binary will automatically search for any `phpmetro.xml` at the root folder and load it unless you specify a location, you can use that to use and run several different configurations and suites.\n\n```console\n$ ./vendor/bin/phpmetro path/to/config.xml\n```\n\n### Configuring\nThe *.xml* config file specifies general run directives for the PHPMetro binary as well as defines the analyses by suite groups.\n\nThe default file can be environment specific: `phpmetro.xml.local` will override `phpmetro.xml.dist` and this will override `phpmetro.xml`.\n\n1. [Configuring PHPMetro](#Configuring-PHPMetro)\n2. [Configuring Suites](#Configuring-Suites)\n\n#### Configuring PHPMetro\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\n\u003cphpmetro\n    verbose=\"true\" \n\u003e\n\n    ...\n\n\u003c/phpmetro\u003e\n\n```\n\nThe two attributes you see are required and they mean:\n- **verbose**: When set to \"true\" PHPMetro will display additional run info. Equals to running the command with the `-v` flag.\n\nThere are no more run configurations. The runner will automatically fetch files from the suites you define. You can set more configurations per suite.\n\n#### Configuring Suites\n```xml\n\u003csuites\u003e\n    \u003csuite\n        name=\"My Analysis Suite\"\n        suffix=\"Suffix\"\n        ignore=\"false\"\n    \u003e\n        \u003cnamespace\u003eMyApp\\Tests\\Metro\u003c/namespace\u003e\n        \u003cdirectory\u003etests/Metro\u003c/directory\u003e\n    \u003c/suite\u003e\n\u003c/suites\u003e\n\n```\n\nSuites must be inside the `\u003csuites\u003e` tag. Each suite accepts the following attributes:\n- **name**: The display name of the suite. Required.\n- **suffix**: Any combinations of letters that the analysis class files use as suffix. Optional. Defaults to \"Analysis\".\n- **ignore**: When set to \"true\" it will indicate the runner to skip the execution of that suite. Optional. Defaults to \"false\".\n\n\u003e**NOTE**: Suffixes don't necessarily have to include the '.php' file extension. In fact the suite right-trims it from the suffix.\n\nInside each suite there must be two more tags specificating:\n- **namespace**: The common namespace for the suite classes.\n- **directory**: The folder where all the classes are at.\n\n\u003e**NOTE**: You must adhere to the [PSR-4](https://getcomposer.org/doc/04-schema.md#psr-4) specification when filenaming your Analyses. If you have an Analysis with the namespace `MyApp\\Tests\\Foo\\BarAnalysis`, for this class to be properly identified by PHPMetro it will have to be located at `tests/Foo/BarAnalysis.php`.\n\n## Usage\nSay you have your own random number generator, `MyApp\\RandomNumber`, and want to see some statistics about it. PHPMetro is your package for that! Let's put it under \"Analysis\".\n\n### Creating an Analysis class\nAn *Analysis* is an special class that extends from `AnalysisCase` and contains a set up with samples and several tests over the samples.\n\n```php\n\u003c?php\n# tests/RandomNumber/RandomNumberAnalysis.php\nnamespace MyApp\\Tests\\RandomNumber;\n\nuse MyApp\\RandomNumber;\nuse PHPMetro\\Analysis\\AnalysisCase;\n\nclass RandomNumberAnalysis extends AnalysisCase\n{\n    # ...\n}\n```\n\nCongratulations, you just created your very first Analysis. But just like that it's pretty much useless. Now you need to add some Samples to your Analysis.\n\n### Adding Sample data\n\nA *Sample* is an special array inside the `AnalysisCase` class that contains sample data from a given set of functions. On your Analysis class add:\n\n```php\npublic function setUp(): void\n{\n    $this-\u003eaddSample('RandomNumber', 100, function(): int {\n        $randomNumber = new RandomNumber();\n\n        return $randomNumber-\u003enew();\n    });\n}\n```\n\nTo add data to a sample we use the `addSample` function, this function takes exactly 3 parameters:\n\n- **$name**: The sample name. String.\n- **$size**: The sample size in number of records, i.e the number of times to perform the function. Integer.\n- **$function**: The function to be run on each iteration of the sample. Needs to specify a return a value. Callable.\n\n\u003e**NOTE**: Function calls that don't specify a return a value will not generate a Sample.\n\nThe `setUp` method is required by the `AnalysisInterface`. All analyses must implement this method with the purpose of being run before test methods in the Analysis.\n\nYou can call to `addSample` anywhere inside your class methods actually, this function will hold the execution of the runner until it finishes adding records. However it is recommended that you add your Samples on set up for performance and maintainability reasons.\n\n\u003e**NOTE**: Unlike other testing frameworks and libraries, PHPMetro will run the method `setUp` only once before running all tests instead of once before each test.\n\nNow that there is Sample data we can start performing some calculations on it. For that you must simply just add Test methods in your class.\n\n### Writing Test methods\n\nA *Test* is an special class method inside your Analysis class that performs some kind of calculation and returns the result. These methods must match the regular expression `test[A-Za-z09]*` and return a basic data type.\n\n\u003e**WARNING**: Tests that return complex data types such as arrays or objects that can't be typecasted to strings will throw an error exception and stop the PHPMetro run.\n\n\u003e**NOTE**: Tests that don't specify a return type will be ignored and not executed.\n\nFor example, we want to test what's the median average of the generated random numbers.\n\nOur Analysis class should look like this:\n\n```php\n\u003c?php\n# tests/RandomNumber/RandomNumberAnalysis.php\nnamespace MyApp\\Tests\\RandomNumber;\n\n// MathPHP provides nice maths\nuse MathPHP\\Statistics\\Average;\n\nuse MyApp\\RandomNumber;\nuse PHPMetro\\Analysis\\AnalysisCase;\n\nclass RandomNumberAnalysis extends AnalysisCase\n{\n    public function setUp(): void\n    {\n        $this-\u003eaddSample('RandomNumbers', 100, function() {\n            $randomNumber = new RandomNumber();\n\n            return $randomNumber-\u003enew();\n        });\n    }\n\n    public function testMedianAverage(): int\n    {\n        $sample = $this-\u003egetSample('RandomNumbers');\n\n        return Average::median($sample);\n    }\n}\n```\n\nTo calculate it we first accessed the sample we added on set up with `getSample`, and then passed it to [MathPHP](https://packagist.org/packages/markrogoyski/math-php)'s `Average` to calculate the median for us.\n\nYou can keep writing more Tests to calculate different things with your Samples. Write Tests as you need them.\n\nFinally, to run the Analyses just run the binary:\n\n```console\n$ ./vendor/bin/phpmetro\n```\n\nYour Tests results should start appearing on your console screen.\n\n![PHPMetro on console](https://user-images.githubusercontent.com/61125897/85226898-24ceda80-b3da-11ea-892f-72c6d84e8a2e.png)\n\n\u003eYou can check more usage examples inside `tests/Self` folder. Which is the self analysis suite described in `tests/phpmetro.xml`.\n\n## Support\nYou can support this project by contributing to open issues or creating pull requests to improve/fix existing code. Contributors are welcome.\n\nIf you liked this package give it a star or tell a friend about it.\n\nIf you have any doubt or commentary, [contact me](mailto:subiabrewd@mail.com).\n\nThank you!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubiabre%2Fphpmetro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubiabre%2Fphpmetro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubiabre%2Fphpmetro/lists"}