Skip to content

Commit a596711

Browse files
committed
chore: add PHP CS Fixer and development documentation
1 parent fd8043a commit a596711

File tree

6 files changed

+276
-26
lines changed

6 files changed

+276
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/.phpunit.cache/
55
/coverage/
66
.DS_Store
7+
/.php-cs-fixer.cache
78

89
# Docker
910
.env

.php-cs-fixer.dist.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
$finder = PhpCsFixer\Finder::create()
6+
->in(__DIR__ . '/src')
7+
->name('*.php')
8+
->ignoreDotFiles(true)
9+
->ignoreVCS(true);
10+
11+
return new PhpCsFixer\Config()
12+
->setRules([
13+
'@PSR12' => true,
14+
'@PHP84Migration' => true,
15+
'array_syntax' => ['syntax' => 'short'],
16+
'blank_line_after_namespace' => true,
17+
'blank_line_after_opening_tag' => true,
18+
'declare_strict_types' => true,
19+
'no_unused_imports' => true,
20+
'ordered_imports' => ['sort_algorithm' => 'alpha'],
21+
'single_quote' => true,
22+
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'arguments', 'parameters']],
23+
'no_empty_statement' => true,
24+
'no_extra_blank_lines' => true,
25+
'no_trailing_whitespace' => true,
26+
'no_whitespace_in_blank_line' => true,
27+
'return_type_declaration' => ['space_before' => 'none'],
28+
'visibility_required' => ['elements' => ['method', 'property']],
29+
'native_function_invocation' => [
30+
'include' => ['@compiler_optimized'],
31+
'scope' => 'namespaced',
32+
],
33+
])
34+
->setFinder($finder)
35+
->setRiskyAllowed(true)
36+
->setUsingCache(true)
37+
->setCacheFile(__DIR__ . '/.php-cs-fixer.cache');

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Added
11+
- Initial implementation of Result type with Ok and Err variants
12+
- Comprehensive API matching Rust's Result type design
13+
- Full PHPDoc annotations for better IDE support
14+
- PHPStan level 9 static analysis
15+
- GitHub Actions CI/CD pipeline
16+
- Comprehensive documentation with usage examples
17+
18+
### Security
19+
- Added roave/security-advisories for dependency vulnerability checking
20+
21+
## [0.1.0] - TBD
22+
23+
Initial release
24+
25+
[Unreleased]: https://github.com/valbeat/php-result/compare/v0.1.0...HEAD
26+
[0.1.0]: https://github.com/valbeat/php-result/releases/tag/v0.1.0

LICENSE

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
1-
This is free and unencumbered software released into the public domain.
1+
MIT License
22

3-
Anyone is free to copy, modify, publish, use, compile, sell, or
4-
distribute this software, either in source code form or as a compiled
5-
binary, for any purpose, commercial or non-commercial, and by any
6-
means.
3+
Copyright (c) 2024 valbeat
74

8-
In jurisdictions that recognize copyright laws, the author or authors
9-
of this software dedicate any and all copyright interest in the
10-
software to the public domain. We make this dedication for the benefit
11-
of the public at large and to the detriment of our heirs and
12-
successors. We intend this dedication to be an overt act of
13-
relinquishment in perpetuity of all present and future rights to this
14-
software under copyright law.
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
1511

16-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19-
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21-
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22-
OTHER DEALINGS IN THE SOFTWARE.
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
2314

24-
For more information, please refer to <https://unlicense.org>
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 185 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,195 @@
1-
# php-result
1+
# PHP Result
22

3-
Result type for PHP inspired by Rust's Result<T, E> type.
3+
[![Latest Stable Version](https://poser.pugx.org/valbeat/result/v)](https://packagist.org/packages/valbeat/result)
4+
[![License](https://poser.pugx.org/valbeat/result/license)](https://packagist.org/packages/valbeat/result)
5+
[![PHP Version Require](https://poser.pugx.org/valbeat/result/require/php)](https://packagist.org/packages/valbeat/result)
6+
7+
A Result type implementation for PHP inspired by Rust's `Result<T, E>` type.
8+
9+
This library provides a robust way to handle operations that might fail, without relying on exceptions. It encourages explicit error handling and makes it impossible to accidentally ignore errors.
10+
11+
## Installation
12+
13+
```bash
14+
composer require valbeat/result
15+
```
416

517
## Requirements
618

719
- PHP 8.4 or higher
820
- Composer
921

10-
## Installation
22+
## Basic Usage
23+
24+
```php
25+
use Valbeat\Result\Ok;
26+
use Valbeat\Result\Err;
27+
use Valbeat\Result\Result;
28+
29+
// Creating Results
30+
$success = new Ok(42);
31+
$failure = new Err("Something went wrong");
32+
33+
// Pattern matching with match expression
34+
$message = $success->match(
35+
ok: fn($value) => "Success: $value",
36+
err: fn($error) => "Error: $error"
37+
);
38+
echo $message; // "Success: 42"
39+
40+
// Checking if a Result is Ok or Err
41+
if ($success->isOk()) {
42+
echo "Operation succeeded!";
43+
}
44+
45+
if ($failure->isErr()) {
46+
echo "Operation failed!";
47+
}
48+
49+
// Unwrapping values (throws exception on error)
50+
$value = $success->unwrap(); // 42
51+
// $failure->unwrap(); // throws LogicException
52+
53+
// Safe unwrapping with default values
54+
$value = $failure->unwrapOr(0); // 0
55+
$value = $failure->unwrapOrElse(fn($err) => strlen($err)); // 19
56+
```
57+
58+
## Advanced Usage
59+
60+
### Transforming Results
61+
62+
```php
63+
// Map over success values
64+
$result = (new Ok(5))
65+
->map(fn($x) => $x * 2)
66+
->map(fn($x) => $x + 1);
67+
echo $result->unwrap(); // 11
68+
69+
// Map over error values
70+
$result = (new Err("error"))
71+
->mapErr(fn($e) => strtoupper($e));
72+
echo $result->unwrapErr(); // "ERROR"
73+
```
74+
75+
### Chaining Operations
76+
77+
```php
78+
// Chain operations that might fail
79+
$result = (new Ok(10))
80+
->andThen(fn($x) => $x > 5 ? new Ok($x * 2) : new Err("Too small"))
81+
->andThen(fn($x) => new Ok($x + 5));
82+
echo $result->unwrap(); // 25
83+
84+
// Short-circuit on first error
85+
$result = (new Ok(2))
86+
->andThen(fn($x) => $x > 5 ? new Ok($x * 2) : new Err("Too small"));
87+
echo $result->unwrapErr(); // "Too small"
88+
```
89+
90+
### Combining Results
91+
92+
```php
93+
// Use first Ok value
94+
$result = (new Err("first error"))
95+
->or(new Err("second error"))
96+
->or(new Ok(42));
97+
echo $result->unwrap(); // 42
98+
99+
// Use first Ok or call function
100+
$result = (new Err("error"))
101+
->orElse(fn($e) => new Ok(strlen($e)));
102+
echo $result->unwrap(); // 5
103+
```
104+
105+
### Side Effects
106+
107+
```php
108+
// Inspect values without consuming the Result
109+
$result = (new Ok(42))
110+
->inspect(fn($x) => print("Value is: $x\n"))
111+
->map(fn($x) => $x * 2);
112+
113+
// Inspect errors
114+
$result = (new Err("oops"))
115+
->inspectErr(fn($e) => error_log("Error occurred: $e"));
116+
```
117+
118+
## API Reference
119+
120+
### Result Methods
121+
122+
All Result types (both Ok and Err) implement these methods:
123+
124+
#### Type Checking
125+
- `isOk(): bool` - Returns true if the Result is Ok
126+
- `isOkAnd(callable $fn): bool` - Returns true if the Result is Ok and the predicate returns true
127+
- `isErr(): bool` - Returns true if the Result is Err
128+
- `isErrAnd(callable $fn): bool` - Returns true if the Result is Err and the predicate returns true
129+
130+
#### Value Extraction
131+
- `unwrap(): mixed` - Returns the success value or throws LogicException
132+
- `unwrapErr(): mixed` - Returns the error value or throws LogicException
133+
- `unwrapOr(mixed $default): mixed` - Returns the success value or a default
134+
- `unwrapOrElse(callable $fn): mixed` - Returns the success value or computes it from the error
135+
136+
#### Transformation
137+
- `map(callable $fn): Result` - Maps a Result<T, E> to Result<U, E> by applying a function to the success value
138+
- `mapErr(callable $fn): Result` - Maps a Result<T, E> to Result<T, F> by applying a function to the error value
139+
- `mapOr(mixed $default, callable $fn): mixed` - Maps the success value or returns a default
140+
- `mapOrElse(callable $defaultFn, callable $fn): mixed` - Maps the success value or computes a default from the error
141+
142+
#### Combination
143+
- `and(Result $res): Result` - Returns the second Result if the first is Ok, otherwise returns the first Err
144+
- `andThen(callable $fn): Result` - Chains another operation that returns a Result
145+
- `or(Result $res): Result` - Returns the first Ok or the second Result if the first is Err
146+
- `orElse(callable $fn): Result` - Returns the first Ok or calls a function with the error to produce a Result
147+
148+
#### Side Effects
149+
- `inspect(callable $fn): Result` - Calls a function with the success value if Ok
150+
- `inspectErr(callable $fn): Result` - Calls a function with the error value if Err
151+
152+
#### Pattern Matching
153+
- `match(callable $okFn, callable $errFn): mixed` - Pattern match on the Result
11154

155+
## Comparison with Rust
156+
157+
This implementation closely follows Rust's Result type design:
158+
159+
| Rust | PHP Result |
160+
|------|------------|
161+
| `Result<T, E>` | `Result<T, E>` |
162+
| `Ok(T)` | `new Ok(T)` |
163+
| `Err(E)` | `new Err(E)` |
164+
| `is_ok()` | `isOk()` |
165+
| `is_err()` | `isErr()` |
166+
| `unwrap()` | `unwrap()` |
167+
| `unwrap_or()` | `unwrapOr()` |
168+
| `map()` | `map()` |
169+
| `and_then()` | `andThen()` |
170+
| `match` expression | `match()` method |
171+
172+
## Development
173+
174+
### Running Tests
175+
```bash
176+
composer test
177+
```
178+
179+
### Static Analysis
12180
```bash
13-
composer install
181+
composer phpstan
14182
```
183+
184+
### Run All Checks
185+
```bash
186+
composer check
187+
```
188+
189+
## License
190+
191+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
192+
193+
## Contributing
194+
195+
Contributions are welcome! Please feel free to submit a Pull Request.

composer.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@
33
"description": "A Result type implementation for PHP inspired by Rust",
44
"type": "library",
55
"license": "MIT",
6+
"keywords": ["result", "rust", "error-handling", "type", "monad", "functional"],
7+
"homepage": "https://github.com/valbeat/php-result",
68
"authors": [
79
{
8-
"name": "valbeat"
10+
"name": "valbeat",
11+
"email": "[email protected]"
912
}
1013
],
1114
"require": {
1215
"php": "^8.4"
1316
},
1417
"require-dev": {
1518
"phpstan/phpstan": "^2.0",
16-
"phpunit/phpunit": "^11.5 || ^12.0"
19+
"phpunit/phpunit": "^11.5 || ^12.0",
20+
"roave/security-advisories": "dev-latest",
21+
"friendsofphp/php-cs-fixer": "^3.64"
1722
},
1823
"autoload": {
1924
"psr-4": {
@@ -28,8 +33,11 @@
2833
"scripts": {
2934
"test": "phpunit",
3035
"phpstan": "phpstan analyse",
36+
"cs-fix": "php-cs-fixer fix --verbose",
37+
"cs-check": "php-cs-fixer fix --verbose --dry-run",
3138
"check": [
3239
"@phpstan",
40+
"@cs-check",
3341
"@test"
3442
]
3543
},

0 commit comments

Comments
 (0)