# Technical Documentation: sebastianbergmann/environment

> ℹ️ **Provenance:** In-Tree Documentation (13 Chapters) · [CodeWiki Reference](https://codewiki.google/github.com/sebastianbergmann/environment) · Recency: Active (< 180 days)

## File: README.md

[](https://packagist.org/packages/sebastian/environment)
[](https://github.com/sebastianbergmann/environment/actions)
[](https://codecov.io/gh/sebastianbergmann/environment)

# sebastian/environment

This component provides functionality that helps writing PHP code that has runtime-specific (PHP / HHVM) execution paths.

## Installation

You can add this library as a local, per-project dependency to your project using [Composer](https://getcomposer.org/):

```
composer require sebastian/environment
```

If you only need this library during development, for instance to run your project's test suite, then you should add it as a development-time dependency:

```
composer require --dev sebastian/environment
```

---

## File: ChangeLog.md

# Changes in sebastianbergmann/environment

All notable changes in `sebastianbergmann/environment` are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.

## [9.3.3] - 2026-10-01

### Changed

* [#98](https://github.com/sebastianbergmann/environment/pull/98): `Runtime::getCurrentSettings()` no longer spawns a child process to determine the built-in default values of INI settings on PHP 8.6 and later

## [9.3.2] - 2026-05-25

### Fixed

* [#99](https://github.com/sebastianbergmann/environment/issues/99): `Runtime::getCurrentSettings()` forwards empty-string overrides for php.ini-only extensions

## [9.3.1] - 2026-05-21

### Fixed

* [#64](https://github.com/sebastianbergmann/environment/issues/64): `Runtime::getCurrentSettings()` does not quote values, breaking `php -d` round-trip

## [9.3.0] - 2026-04-15

### Added

* `Runtime::getSettingsNotChangeableAtRuntime()`

## [9.2.0] - 2026-04-05

### Added

* [`#80`](https://github.com/sebastianbergmann/environment/issues/80): Support for `FORCE_COLOR` environment variable

## [9.1.0] - 2026-03-22

### Added

* `Host` class

## [9.0.1] - 2026-03-15

### Fixed

* [#79](https://github.com/sebastianbergmann/environment/issues/79): Warnings in non-TTY environments

## [9.0.0] - 2026-02-06

### Removed

* This component is no longer supported on PHP 8.3

## [8.1.2] - 2026-05-25

### Fixed

* [#99](https://github.com/sebastianbergmann/environment/issues/99): `Runtime::getCurrentSettings()` forwards empty-string overrides for php.ini-only extensions

## [8.1.1] - 2026-05-21

### Fixed

* [#64](https://github.com/sebastianbergmann/environment/issues/64): `Runtime::getCurrentSettings()` does not quote values, breaking `php -d` round-trip

## [8.1.0] - 2026-04-15

### Added

* `Runtime::getSettingsNotChangeableAtRuntime()`

## [8.0.4] - 2026-03-15

### Fixed

* [#79](https://github.com/sebastianbergmann/environment/issues/79): Warnings in non-TTY environments

## [8.0.3] - 2025-08-12

### Changed

* [#75](https://github.com/sebastianbergmann/environment/pull/75): Make `Runtime::isOpcacheActive()` public

## [8.0.2] - 2025-05-21

### Fixed

* [#74](https://github.com/sebastianbergmann/environment/pull/74): Regression introduced in version 8.0.0

## [8.0.1] - 2025-05-21

### Fixed

* Take Xdebug mode into account for `Runtime::canCollectCodeCoverage()`

## [8.0.0] - 2025-02-07

### Removed

* This component is no longer supported on PHP 8.2

## [7.2.1] - 2025-05-21

### Fixed

* Take Xdebug mode into account for `Runtime::canCollectCodeCoverage()`

## [7.2.0] - 2024-07-03

### Changed

* Synced `Console::hasColorSupport()` with Symfony's `StreamOutput::hasColorSupport()` implementation
* Removed code left over from a time before PHP 5.4 and when HHVM was still supported
* This project now uses PHPStan instead of Psalm for static analysis

### Deprecated

* The `Runtime::getBinary()` method is now deprecated, use `escapeshellarg(PHP_BINARY)` instead
* The `Runtime::getRawBinary()` method is now deprecated, use the `PHP_BINARY` constant instead

## [7.1.0] - 2024-03-23

### Added

* [#72](https://github.com/sebastianbergmann/environment/pull/72): `Runtime::getRawBinary()`

## [7.0.0] - 2024-02-02

### Removed

* This component is no longer supported on PHP 8.1

## [6.1.1] - 2024-MM-DD

### Changed

* Synced `Console::hasColorSupport()` with Symfony's `StreamOutput::hasColorSupport()` implementation

## [6.1.0] - 2024-03-23

### Added

* [#72](https://github.com/sebastianbergmann/environment/pull/72): `Runtime::getRawBinary()`

## [6.0.1] - 2023-04-11

### Fixed

* [#68](https://github.com/sebastianbergmann/environment/pull/68): The Just-in-Time compiler is disabled when `opcache.jit_buffer_size` is set to `0`
* [#70](https://github.com/sebastianbergmann/environment/pull/70): The first `0` of `opcache.jit` only disables CPU-specific optimizations, not the Just-in-Time compiler itself

## [6.0.0] - 2023-02-03

### Removed

* Removed `SebastianBergmann\Environment\OperatingSystem::getFamily()` because this component is no longer supported on PHP versions that do not have `PHP_OS_FAMILY`
* Removed `SebastianBergmann\Environment\Runtime::isHHVM()`
* This component is no longer supported on PHP 7.3, PHP 7.4, and PHP 8.0

## [5.1.5] - 2022-MM-DD

### Fixed

* [#59](https://github.com/sebastianbergmann/environment/issues/59): Wrong usage of `stream_isatty()`, `fstat()` used without checking whether the function is available

## [5.1.4] - 2022-04-03

### Fixed

* [#63](https://github.com/sebastianbergmann/environment/pull/63): `Runtime::getCurrentSettings()` does not correctly process INI settings

## [5.1.3] - 2020-09-28

### Changed

* Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3`

## [5.1.2] - 2020-06-26

### Added

* This component is now supported on PHP 8

## [5.1.1] - 2020-06-15

### Changed

* Tests etc. are now ignored for archive exports

## [5.1.0] - 2020-04-14

### Added

* `Runtime::performsJustInTimeCompilation()` returns `true` if PHP 8's JIT is active, `false` otherwise

## [5.0.2] - 2020-03-31

### Fixed

* [#55](https://github.com/sebastianbergmann/environment/issues/55): `stty` command is executed even if no tty is available

## [5.0.1] - 2020-02-19

### Changed

* `Runtime::getNameWithVersionAndCodeCoverageDriver()` now prioritizes PCOV over Xdebug when both extensions are loaded (just like php-code-coverage does)

## [5.0.0] - 2020-02-07

### Removed

* This component is no longer supported on PHP 7.1 and PHP 7.2

## [4.2.3] - 2019-11-20

### Changed

* [#50](https://github.com/sebastianbergmann/environment/pull/50): Windows improvements to console capabilities

### Fixed

* [#49](https://github.com/sebastianbergmann/environment/issues/49): Detection how OpCache handles docblocks does not work correctly when PHPDBG is used

## [4.2.2] - 2019-05-05

### Fixed

* [#44](https://github.com/sebastianbergmann/environment/pull/44): `TypeError` in `Console::getNumberOfColumnsInteractive()`

## [4.2.1] - 2019-04-25

### Fixed

* Fixed an issue in `Runtime::getCurrentSettings()`

## [4.2.0] - 2019-04-25

### Added

* [#36](https://github.com/sebastianbergmann/environment/pull/36): `Runtime::getCurrentSettings()`

## [4.1.0] - 2019-02-01

### Added

* Implemented `Runtime::getNameWithVersionAndCodeCoverageDriver()` method
* [#34](https://github.com/sebastianbergmann/environment/pull/34): Support for PCOV extension

## [4.0.2] - 2019-01-28

### Fixed

* [#33](https://github.com/sebastianbergmann/environment/issues/33): `Runtime::discardsComments()` returns true too eagerly

### Removed

* Removed support for Zend Optimizer+ in `Runtime::discardsComments()`

## [4.0.1] - 2018-11-25

### Fixed

* [#31](https://github.com/sebastianbergmann/environment/issues/31): Regressions in `Console` class

## [4.0.0] - 2018-10-23 [YANKED]

### Fixed

* [#25](https://github.com/sebastianbergmann/environment/pull/25): `Console::hasColorSupport()` does not work on Windows

### Removed

* This component is no longer supported on PHP 7.0

## [3.1.0] - 2017-07-01

### Added

* [#21](https://github.com/sebastianbergmann/environment/issues/21): Equivalent of `PHP_OS_FAMILY` (for PHP < 7.2) 

## [3.0.4] - 2017-06-20

### Fixed

* [#20](https://github.com/sebastianbergmann/environment/pull/20): PHP 7 mode of HHVM not forced

## [3.0.3] - 2017-05-18

### Fixed

* [#18](https://github.com/sebastianbergmann/environment/issues/18): `Uncaught TypeError: preg_match() expects parameter 2 to be string, null given`

## [3.0.2] - 2017-04-21

### Fixed

* [#17](https://github.com/sebastianbergmann/environment/issues/17): `Uncaught TypeError: trim() expects parameter 1 to be string, boolean given`

## [3.0.1] - 2017-04-21

### Fixed

* Fixed inverted logic in `Runtime::discardsComments()`

## [3.0.0] - 2017-04-21

### Added

* Implemented `Runtime::discardsComments()` for querying whether the PHP runtime discards annotations

### Removed

* This component is no longer supported on PHP 5.6

[9.3.3]: https://github.com/sebastianbergmann/environment/compare/9.3.2...9.3.3
[9.3.2]: https://github.com/sebastianbergmann/environment/compare/9.3.1...9.3.2
[9.3.1]: https://github.com/sebastianbergmann/environment/compare/9.3.0...9.3.1
[9.3.0]: https://github.com/sebastianbergmann/environment/compare/9.2.0...9.3.0
[9.2.0]: https://github.com/sebastianbergmann/environment/compare/9.1.0...9.2.0
[9.1.0]: https://github.com/sebastianbergmann/environment/compare/9.0.1...9.1.0
[9.0.1]: https://github.com/sebastianbergmann/environment/compare/9.0.0...9.0.1
[9.0.0]: https://github.com/sebastianbergmann/environment/compare/8.1...9.0.0
[8.1.2]: https://github.com/sebastianbergmann/environment/compare/8.1.1...8.1.2
[8.1.1]: https://github.com/sebastianbergmann/environment/compare/8.1.0...8.1.1
[8.1.0]: https://github.com/sebastianbergmann/environment/compare/8.0.4...8.1.0
[8.0.4]: https://github.com/sebastianbergmann/environment/compare/8.0.3...8.0.4
[8.0.4]: https://github.com/sebastianbergmann/environment/compare/8.0.3...8.0
[8.0.3]: https://github.com/sebastianbergmann/environment/compare/8.0.2...8.0.3
[8.0.2]: https://github.com/sebastianbergmann/environment/compare/8.0.1...8.0.2
[8.0.1]: https://github.com/sebastianbergmann/environment/compare/8.0.0...8.0.1
[8.0.0]: https://github.com/sebastianbergmann/environment/compare/7.2...8.0.0
[7.2.1]: https://github.com/sebastianbergmann/environment/compare/7.2.0...7.2.1
[7.2.0]: https://github.com/sebastianbergmann/environment/compare/7.1.0...7.2.0
[7.1.0]: https://github.com/sebastianbergmann/environment/compare/7.0.0...7.1.0
[7.0.0]: https://github.com/sebastianbergmann/environment/compare/6.1...7.0.0
[6.1.1]: https://github.com/sebastianbergmann/environment/compare/6.1.0...6.1
[6.1.0]: https://github.com/sebastianbergmann/environment/compare/6.0.1...6.1.0
[6.0.1]: https://github.com/sebastianbergmann/environment/compare/6.0.0...6.0.1
[6.0.0]: https://github.com/sebastianbergmann/environment/compare/5.1.5...6.0.0
[5.1.5]: https://github.com/sebastianbergmann/environment/compare/5.1.4...5.1.5
[5.1.4]: https://github.com/sebastianbergmann/environment/compare/5.1.3...5.1.4
[5.1.3]: https://github.com/sebastianbergmann/environment/compare/5.1.2...5.1.3
[5.1.2]: https://github.com/sebastianbergmann/environment/compare/5.1.1...5.1.2
[5.1.1]: https://github.com/sebastianbergmann/environment/compare/5.1.0...5.1.1
[5.1.0]: https://github.com/sebastianbergmann/environment/compare/5.0.2...5.1.0
[5.0.2]: https://github.com/sebastianbergmann/environment/compare/5.0.1...5.0.2
[5.0.1]: https://github.com/sebastianbergmann/environment/compare/5.0.0...5.0.1
[5.0.0]: https://github.com/sebastianbergmann/environment/compare/4.2.3...5.0.0
[4.2.3]: https://github.com/sebastianbergmann/environment/compare/4.2.2...4.2.3
[4.2.2]: https://github.com/sebastianbergmann/environment/compare/4.2.1...4.2.2
[4.2.1]: https://github.com/sebastianbergmann/environment/compare/4.2.0...4.2.1
[4.2.0]: https://github.com/sebastianbergmann/environment/compare/4.1.0...4.2.0
[4.1.0]: https://github.com/sebastianbergmann/environment/compare/4.0.2...4.1.0
[4.0.2]: https://github.com/sebastianbergmann/environment/compare/4.0.1...4.0.2
[4.0.1]: https://github.com/sebastianbergmann/environment/compare/66691f8e2dc4641909166b275a9a4f45c0e89092...4.0.1
[4.0.0]: https://github.com/sebastianbergmann/environment/compare/3.1.0...66691f8e2dc4641909166b275a9a4f45c0e89092
[3.1.0]: https://github.com/sebastianbergmann/environment/compare/3.0...3.1.0
[3.0.4]: https://github.com/sebastianbergmann/environment/compare/3.0.3...3.0.4
[3.0.3]: https://github.com/sebastianbergmann/environment/compare/3.0.2...3.0.3
[3.0.2]: https://github.com/sebastianbergmann/environment/compare/3.0.1...3.0.2
[3.0.1]: https://github.com/sebastianbergmann/environment/compare/3.0.0...3.0.1
[3.0.0]: https://github.com/sebastianbergmann/environment/compare/2.0...3.0.0

---

## File: composer.json

{
    "name": "sebastian/environment",
    "description": "Provides functionality to handle HHVM/PHP environments",
    "keywords": ["environment","hhvm","xdebug"],
    "homepage": "https://github.com/sebastianbergmann/environment",
    "license": "BSD-3-Clause",
    "authors": [
        {
            "name": "Sebastian Bergmann",
            "email": "sebastian@phpunit.de"
        }
    ],
    "support": {
        "issues": "https://github.com/sebastianbergmann/environment/issues",
        "security": "https://github.com/sebastianbergmann/environment/security/policy"
    },
    "config": {
        "platform": {
            "php": "8.4.1"
        },
        "optimize-autoloader": true,
        "sort-packages": true
    },
    "prefer-stable": true,
    "require": {
        "php": ">=8.4"
    },
    "require-dev": {
        "phpunit/phpunit": "^13.4.3"
    },
    "suggest": {
        "ext-posix": "*"
    },
    "autoload": {
        "classmap": [
            "src/"
        ]
    },
    "extra": {
        "branch-alias": {
            "dev-main": "9.3-dev"
        }
    }
}

---

## File: renovate.json

{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "extends": [
        "config:recommended",
        "helpers:pinGitHubActionDigestsToSemver",
        ":configMigration"
    ],
    "timezone": "Europe/Berlin",
    "baseBranchPatterns": [
        "main",
        "/^\\d+\\.\\d+$/"
    ],
    "rebaseWhen": "conflicted",
    "prHourlyLimit": 2,
    "prConcurrentLimit": 10,
    "dependencyDashboard": true,
    "labels": ["type/dependencies"],
    "platformAutomerge": true,
    "osvVulnerabilityAlerts": true,
    "dependencyDashboardOSVVulnerabilitySummary": "all",
    "vulnerabilityAlerts": {
        "enabled": true,
        "labels": ["type/security", "type/dependencies"]
    },
    "packageRules": [
        {
            "description": "Group GitHub Actions updates per branch into one PR, automerge",
            "matchManagers": ["github-actions"],
            "groupName": "github-actions",
            "automerge": true
        },
        {
            "description": "Automerge minor and patch updates after they have settled",
            "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
            "automerge": true
        },
        {
            "description": "Do not update the PHP platform requirement in composer.json",
            "matchManagers": ["composer"],
            "matchDepNames": ["php"],
            "enabled": false
        },
        {
            "description": "Do not suggest major updates for Composer dependencies",
            "matchManagers": ["composer"],
            "matchUpdateTypes": ["major"],
            "enabled": false
        },
        {
            "description": "Bump composer.json ranges when updating dependencies",
            "matchManagers": ["composer"],
            "rangeStrategy": "bump"
        }
    ]
}

---

## File: SECURITY.md

# Security Policy

The library that is developed in this repository is a first-party dependency of [PHPUnit](https://github.com/sebastianbergmann/phpunit).
[PHPUnit's Security Policy](https://github.com/sebastianbergmann/phpunit/security/policy) applies to this library as well.

If you believe you have found a security vulnerability in this library, please report it to me through coordinated disclosure.

Use my [PGP key](https://sebastian-bergmann.de/gpg.asc) for encrypted email, for example when your report includes proof-of-concept exploits against third-party systems.

**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**

---

## File: tools/.phpstan/composer.json

{
    "require-dev": {
        "phpstan/phpstan": "^2.3.1",
        "phpstan/extension-installer": "^1.4.3",
        "phpstan/phpstan-strict-rules": "^2.1.0",
        "ergebnis/phpstan-rules": "^2.14.2"
    },
    "config": {
        "allow-plugins": {
            "phpstan/extension-installer": true
        }
    }
}

---

## File: .github/CODE_OF_CONDUCT.md

# Contributor Code of Conduct

As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
  addresses, without explicit permission
* Other unethical or unprofessional conduct

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer at sebastian@phpunit.de. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version]

[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/3/0/

---

## File: .github/CONTRIBUTING.md

# Contributing to `sebastian/environment`

## Welcome!

We look forward to your contributions! Here are some examples how you can contribute:

* [Report a bug](https://github.com/sebastianbergmann/environment/issues/new)
* [Send a pull request to fix a bug](https://github.com/sebastianbergmann/environment/pulls)


## We have a Code of Conduct

Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.


## Any contributions you make will be under the BSD-3-Clause License

When you submit code changes, your submissions are understood to be under the same [BSD-3-Clause License](https://github.com/sebastianbergmann/environment/blob/main/LICENSE) that covers the project. By contributing to this project, you agree that your contributions will be licensed under its BSD-3-Clause License.


### Do Not Violate Copyright

Only submit a pull request with your own original code. Do NOT submit a pull request containing code which you have largely copied from
another project, unless you wrote the respective code yourself.

Open Source does not mean that copyright does not apply. Copyright infringements will not be tolerated and can lead to you being banned from this project and repository.


### Do Not Submit AI-Generated Pull Requests

The same goes for (largely) AI-generated pull requests. These are not welcome as they will be based on copyrighted code from others
without accreditation and without taking the license of the original code into account, let alone getting permission
for the use of the code or for re-licensing.

Aside from that, the experience is that AI-generated pull requests will be incorrect 100% of the time and cost reviewers too much time.
Submitting a (largely) AI-generated pull request will lead to you being banned from this project and repository.


## Write bug reports with detail, background, and sample code

[This is an example](https://github.com/sebastianbergmann/phpunit/issues/4376) of a bug report I wrote, and I think it's not too bad.

In your bug report, please provide the following:

* A quick summary and/or background
* Steps to reproduce
    * Be specific!
    * Give sample code if you can.
* What you expected would happen
* What actually happens
* Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)

Please do not report a bug for a version of this library that is no longer supported. Please do not report a bug if you are using a version of PHP that is not supported by the version of this library you are using.

The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit. Support for this library follows the [support for the version of PHPUnit that uses a specific version of this library](https://phpunit.de/supported-versions.html).

Please post code and output as text ([using proper markup](https://guides.github.com/features/mastering-markdown/)). Do not post screenshots of code or output.


## Workflow for Pull Requests

1. Fork the repository.
2. Create your branch from `main` if you plan to implement new functionality or change existing code significantly; create your branch from the oldest branch that is affected by the bug if you plan to fix a bug.
3. Implement your change and add tests for it.
4. Ensure the test suite passes.
5. Ensure the code complies with our coding guidelines (see below).
6. Send that pull request!

Please make sure you have [set up your username and email address](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) for use with Git. Strings such as `silly nick name <root@localhost>` look really stupid in the commit history of a project.

We encourage you to [sign your Git commits with your GPG key](https://docs.github.com/en/github/authenticating-to-github/signing-commits).

Pull requests for bug fixes must be made for the oldest branch that is supported (see above). Pull requests for new features must be based on the `main` branch.

We are trying to keep backwards compatibility breaks to an absolute minimum. Please take this into account when proposing changes.

Due to time constraints, we are not always able to respond as quickly as we would like. Please do not take delays personal and feel free to remind us if you feel that we forgot to respond.


## Development

This project uses [PHPUnit](https://phpunit.de/) for testing:

```shell
./vendor/bin/phpunit
```

This project uses [PHPStan](https://phpstan.org/) for static analysis:

```shell
./tools/phpstan
```

This project uses [PHP-CS-Fixer](https://cs.symfony.com/) to enforce coding guidelines:

```shell
./tools/php-cs-fixer fix
```

The commands shown above require an autoloader script at `vendor/autoload.php`. This can be generated like so:

```shell
./tools/composer dump-autoload
```

Please understand that we will not accept a pull request when its changes violate this project's coding guidelines or break the test suite.

---

## File: .github/FUNDING.yml

github: sebastianbergmann
liberapay: sebastianbergmann
thanks_dev: u/gh/sebastianbergmann
tidelift: "packagist/sebastian/environment"

---

## File: .github/workflows/api-surface-check.yaml

# https://github.com/marketplace/actions/api-surface-check-for-php

on:
  pull_request:
    paths-ignore:
      - ".editorconfig"
      - "LICENSE"
      - "**.md"
      - "**.png"
      - "**.svg"
      - "tests/**"

name: "API Surface Check"

permissions: {}

concurrency:
  group: api-surface-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  signal:
    name: Signal
    runs-on: ubuntu-latest
    steps:
      - run: "true"

---

## File: .github/workflows/api-surface-comment.yaml

# https://github.com/marketplace/actions/api-surface-check-for-php

on:
  # zizmor: ignore[dangerous-triggers] workflow_run is required to comment on
  # PRs from forks; this workflow only runs a pinned action and does not check
  # out PR-controlled code.
  workflow_run:
    workflows: ["API Surface Check"]
    types: [completed]

name: "API Surface Comment"

permissions:
  contents: read

concurrency:
  group: api-surface-comment-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
  cancel-in-progress: true

jobs:
  check-api-surface:
    name: Check API Surface
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write # required to post the API surface diff comment on the PR
    steps:
      - uses: composer/api-surface-check@bba9f1cb940df6e02271b1b6158679ac0b3f39d3 # 1.0.1

---

## File: .github/workflows/ci.yaml

# https://docs.github.com/en/actions

on:
  - pull_request
  - push

name: CI

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  COMPOSER_ROOT_VERSION: 9.3.x-dev
  PHP_VERSION: 8.5

permissions:
  contents: read

jobs:
  coding-guidelines:
    name: Coding Guidelines

    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 1
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - name: Use local branch
        shell: bash
        env:
          EVENT_NAME: ${{ github.event_name }}
          HEAD_REF: ${{ github.head_ref }}
          REF_NAME: ${{ github.ref_name }}
        run: |
          if [ "$EVENT_NAME" = "pull_request" ]; then
            BRANCH="$HEAD_REF"
          else
            BRANCH="$REF_NAME"
          fi
          git branch -D "$BRANCH" 2>/dev/null || true
          git branch "$BRANCH" HEAD
          git checkout "$BRANCH"

      - name: Install PHP
        uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0
        with:
          php-version: ${{ env.PHP_VERSION }}
          coverage: none
          tools: none

      - name: Run PHP-CS-Fixer
        run: ./tools/php-cs-fixer fix --dry-run --show-progress=dots --using-cache=no --verbose

  static-analysis:
    name: Static Analysis

    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 1
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - name: Use local branch
        shell: bash
        env:
          EVENT_NAME: ${{ github.event_name }}
          HEAD_REF: ${{ github.head_ref }}
          REF_NAME: ${{ github.ref_name }}
        run: |
          if [ "$EVENT_NAME" = "pull_request" ]; then
            BRANCH="$HEAD_REF"
          else
            BRANCH="$REF_NAME"
          fi
          git branch -D "$BRANCH" 2>/dev/null || true
          git branch "$BRANCH" HEAD
          git checkout "$BRANCH"

      - name: Install PHP
        uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0
        with:
          php-version: ${{ env.PHP_VERSION }}
          coverage: none
          tools: none

      - name: Install dependencies with Composer
        run: ./tools/composer update --no-interaction --no-ansi --no-progress

      - name: Run PHPStan
        run: ./tools/phpstan analyse --no-progress --error-format=github

  tests:
    name: Tests

    runs-on: ubuntu-latest
    timeout-minutes: 5

    strategy:
      fail-fast: false
      matrix:
        php-version:
          - 8.4
          - 8.5
          - 8.6
          - 8.7
        coverage:
          - none
          - xdebug
          - pcov

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 1
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - name: Use local branch
        shell: bash
        env:
          EVENT_NAME: ${{ github.event_name }}
          HEAD_REF: ${{ github.head_ref }}
          REF_NAME: ${{ github.ref_name }}
        run: |
          if [ "$EVENT_NAME" = "pull_request" ]; then
            BRANCH="$HEAD_REF"
          else
            BRANCH="$REF_NAME"
          fi
          git branch -D "$BRANCH" 2>/dev/null || true
          git branch "$BRANCH" HEAD
          git checkout "$BRANCH"

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0
        with:
          php-version: ${{ matrix.php-version }}
          ini-values: memory_limit=-1, zend.assertions=1, error_reporting=-1, display_errors=On, display_startup_errors=On
          coverage: ${{ matrix.coverage }}
          tools: none

      - name: Get Composer cache directory
        id: composer-cache
        shell: bash
        run: |
          echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"

      - name: Cache Composer cache directory
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies with Composer
        run: ./tools/composer update --no-ansi --no-interaction --no-progress

      - name: Run tests with PHPUnit
        run: vendor/bin/phpunit

  code-coverage:
    name: Code Coverage

    needs:
      - tests

    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 1
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          persist-credentials: false

      - name: Use local branch
        shell: bash
        env:
          EVENT_NAME: ${{ github.event_name }}
          HEAD_REF: ${{ github.head_ref }}
          REF_NAME: ${{ github.ref_name }}
        run: |
          if [ "$EVENT_NAME" = "pull_request" ]; then
            BRANCH="$HEAD_REF"
          else
            BRANCH="$REF_NAME"
          fi
          git branch -D "$BRANCH" 2>/dev/null || true
          git branch "$BRANCH" HEAD
          git checkout "$BRANCH"

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0
        with:
          php-version: ${{ env.PHP_VERSION }}
          ini-values: memory_limit=-1, zend.assertions=1, error_reporting=-1, display_errors=On, display_startup_errors=On
          coverage: xdebug
          tools: none

      - name: Get Composer cache directory
        id: composer-cache
        shell: bash
        run: |
          echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"

      - name: Cache Composer cache directory
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies with Composer
        run: ./tools/composer update --no-ansi --no-interaction --no-progress

      - name: Collect code coverage with PHPUnit
        run: vendor/bin/phpunit --log-junit test-results.xml --coverage-openclover=code-coverage.xml

      - name: Upload test results to Codecov.io
        if: ${{ !cancelled() }}
        uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          report_type: test_results
          disable_search: true
          files: ./test-results.xml

      - name: Upload code coverage data to Codecov.io
        if: ${{ !cancelled() }}
        uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          report_type: coverage
          disable_search: true
          files: ./code-coverage.xml

---

## File: .github/workflows/release.yaml

# https://docs.github.com/en/actions

on:
  push:
    tags:
      - "**"

name: Release

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

permissions:
  contents: read

jobs:
  release:
    name: Release

    runs-on: ubuntu-latest

    permissions:
      contents: write # required to create GitHub releases

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Install PHP with extensions
        uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0
        with:
          php-version: 8.3
          coverage: none
          extensions: none
          tools: none

      - name: Determine tag
        run: echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> "$GITHUB_ENV"

      - name: Parse ChangeLog
        run: build/scripts/extract-release-notes.php "${RELEASE_TAG}" > release-notes.md

      - name: Create release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh release create "${RELEASE_TAG}" --title "sebastian/environment ${RELEASE_TAG}" --notes-file release-notes.md

--- METRICS ---
- Files Extracted: 13
- Estimated Token Budget: ~9546 tokens
- Recency Window: Active (< 180 days)
- Canonical Reference: https://codewiki.google/github.com/sebastianbergmann/environment
