Skip to content

Commit 7130703

Browse files
committed
Refactor: Comprehensive code quality and maintainability improvements
This major refactoring enhances code quality, type safety, and maintainability across the entire library while maintaining backward compatibility. ## Type Safety & Strict Types - Add `declare(strict_types=1)` to all PHP files - Add complete parameter and return type declarations (PHP 8.0+) - Implement union types where appropriate (array|ArrayAccess, string|array) - Add property type declarations ## Enhanced Functionality - **Arr**: Fix exists() logic to properly handle nested arrays and ArrayAccess - **Str**: Improve random string generation for better security and consistency - **Carbon**: Add 6 new helper methods (fromTimestamp, isToday, isPast, isFuture, isBetweenDates, diffInDaysAbsolute) - **Functions**: Update with proper type hints and enhanced documentation ## Documentation - Add comprehensive PHPDoc blocks to all 40+ methods - Include @param, @return, @throws tags with detailed descriptions - Add real-world usage examples in every PHPDoc - Expand README.md with complete usage guide and examples - Add table of contents and feature highlights ## Testing - Add 25+ edge case tests covering: - Empty strings and arrays - Unicode and multi-byte characters - Deeply nested structures - Null, false, and zero values - ArrayAccess objects - Special characters - Very long strings (10,000+ chars) - Add new CarbonTest.php with 7 comprehensive tests - All 63 tests passing (330 assertions) ## Static Analysis & Code Quality - Install and configure PHPStan at Level 8 (strictest) - Create phpstan.neon with comprehensive rules - Create pint.json with PSR-12 + strict coding standards - Add PHPStan to CI workflow - Add new composer scripts: analyze, check, analyze-baseline ## Configuration Updates - Update composer.json with PHPStan and Pest dependencies - Migrate phpunit.xml.dist to PHPUnit 10.5 schema (removes warnings) - Update CI workflow to run static analysis on all builds - Add .gitignore entries for build artifacts ## Breaking Changes None - All changes maintain backward compatibility while adding strict types ## Key Improvements - 100% strict type coverage - PHPStan Level 8 compliant - PSR-12 code style enforced - UTF-8 safe string operations - Modern PHP 8.0+ syntax - Enterprise-grade code quality
1 parent e289dac commit 7130703

19 files changed

Lines changed: 1237 additions & 164 deletions

.github/workflows/run-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
- name: Install dependencies
3434
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction
3535

36+
- name: Run static analysis
37+
run: composer analyze
38+
3639
- name: Execute tests
3740
run: vendor/bin/pest --coverage --coverage-clover=coverage.xml
3841

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.php_cs
55
.php_cs.cache
66
.phpunit.result.cache
7+
.phpunit.cache
78
build
89
composer.lock
910
coverage

README.md

Lines changed: 332 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55
[![codecov](https://codecov.io/gh/farzai/support-php/branch/main/graph/badge.svg)](https://codecov.io/gh/farzai/support-php)
66
[![Total Downloads](https://img.shields.io/packagist/dt/farzai/support.svg?style=flat-square)](https://packagist.org/packages/farzai/support)
77

8+
A collection of useful PHP helper functions and utilities with full type safety and comprehensive documentation.
9+
10+
## Features
11+
12+
- 🔒 **Fully Typed** - Complete PHP 8.0+ type declarations for enhanced IDE support
13+
- 📝 **Well Documented** - Comprehensive PHPDoc comments with examples
14+
-**Thoroughly Tested** - High test coverage with edge case testing
15+
- 🔍 **Static Analysis** - PHPStan Level 8 compliant
16+
- 🎯 **Zero Dependencies** - Only requires Carbon for date/time utilities
17+
- 🌐 **UTF-8 Safe** - Multi-byte string operations throughout
18+
19+
## Requirements
20+
21+
- PHP 8.0 or higher
22+
- ext-mbstring
823

924
## Installation
1025

@@ -14,12 +29,327 @@ You can install the package via composer:
1429
composer require farzai/support
1530
```
1631

17-
## Testing
32+
## Table of Contents
1833

19-
```bash
34+
- [Array Utilities](#array-utilities)
35+
- [String Utilities](#string-utilities)
36+
- [Date/Time Utilities](#datetime-utilities)
37+
- [Helper Functions](#helper-functions)
38+
39+
## Array Utilities
40+
41+
The `Arr` class provides utilities for working with arrays using dot notation.
42+
43+
### get()
44+
45+
Get an item from an array using dot notation:
46+
47+
```php
48+
use Farzai\Support\Arr;
49+
50+
$array = [
51+
'user' => [
52+
'name' => 'John Doe',
53+
'email' => 'john@example.com',
54+
'address' => [
55+
'city' => 'New York'
56+
]
57+
]
58+
];
59+
60+
// Get nested value
61+
Arr::get($array, 'user.name'); // Returns: 'John Doe'
62+
Arr::get($array, 'user.address.city'); // Returns: 'New York'
63+
64+
// With default value
65+
Arr::get($array, 'user.phone', 'N/A'); // Returns: 'N/A'
66+
67+
// Get entire array
68+
Arr::get($array, null); // Returns: entire $array
69+
```
70+
71+
### exists()
72+
73+
Check if a key exists in an array using dot notation:
74+
75+
```php
76+
use Farzai\Support\Arr;
77+
78+
$array = ['user' => ['name' => 'John']];
79+
80+
Arr::exists($array, 'user.name'); // Returns: true
81+
Arr::exists($array, 'user.email'); // Returns: false
82+
```
83+
84+
### accessible()
85+
86+
Check if a value is array accessible:
87+
88+
```php
89+
use Farzai\Support\Arr;
90+
91+
Arr::accessible(['foo' => 'bar']); // Returns: true
92+
Arr::accessible(new ArrayObject()); // Returns: true
93+
Arr::accessible('string'); // Returns: false
94+
```
95+
96+
## String Utilities
97+
98+
The `Str` class provides a rich set of string manipulation methods.
99+
100+
### Case Conversion
101+
102+
```php
103+
use Farzai\Support\Str;
104+
105+
// camelCase
106+
Str::camel('foo_bar'); // Returns: 'fooBar'
107+
Str::camel('foo-bar'); // Returns: 'fooBar'
108+
109+
// StudlyCase (PascalCase)
110+
Str::studly('foo_bar'); // Returns: 'FooBar'
111+
112+
// snake_case
113+
Str::snake('fooBar'); // Returns: 'foo_bar'
114+
Str::snake('FooBar', '-'); // Returns: 'foo-bar'
115+
116+
// lowercase
117+
Str::lower('FOO BAR'); // Returns: 'foo bar'
118+
```
119+
120+
### Case Checking
121+
122+
```php
123+
use Farzai\Support\Str;
124+
125+
Str::isSnakeCase('foo_bar'); // Returns: true
126+
Str::isCamelCase('fooBar'); // Returns: true
127+
Str::isStudlyCase('FooBar'); // Returns: true
128+
```
129+
130+
### String Operations
131+
132+
```php
133+
use Farzai\Support\Str;
134+
135+
// Replace
136+
Str::replace('foo', 'bar', 'foo baz'); // Returns: 'bar baz'
137+
138+
// Check if starts with
139+
Str::startsWith('foobar', 'foo'); // Returns: true
140+
Str::startsWith('foobar', ['bar', 'foo']); // Returns: true
141+
142+
// Check if ends with
143+
Str::endsWith('foobar', 'bar'); // Returns: true
144+
145+
// Check if contains
146+
Str::contains('foobar', 'oob'); // Returns: true
147+
Str::contains('foobar', ['baz', 'bar']); // Returns: true
148+
149+
// Length (UTF-8 safe)
150+
Str::length('foo'); // Returns: 3
151+
Str::length('ñoño'); // Returns: 4
152+
153+
// Substring (UTF-8 safe)
154+
Str::substr('foobar', 0, 3); // Returns: 'foo'
155+
Str::substr('foobar', 3); // Returns: 'bar'
156+
```
157+
158+
### Random String Generation
159+
160+
All random methods use cryptographically secure randomness:
161+
162+
```php
163+
use Farzai\Support\Str;
164+
165+
// Random alphanumeric (base64-like)
166+
Str::random(16); // Returns: 'a3K7mN9pQ1xY2zB5'
167+
168+
// Random ASCII
169+
Str::randomAscii(16);
170+
171+
// Random numeric only
172+
Str::randomNumeric(6); // Returns: '472891'
173+
174+
// Random alphanumeric (A-Z, a-z, 0-9)
175+
Str::randomAlphanumeric(12); // Returns: 'aB3xY9mK2nP7'
176+
177+
// Random with custom character set
178+
Str::randomString(8, 'ABCD123'); // Returns: 'A2B1C3D2'
179+
180+
// Random with special characters (for passwords)
181+
Str::randomStringWithSpecialCharacter(16); // Returns: 'aB3!xY@9#mK2$pQ5'
182+
```
183+
184+
## Date/Time Utilities
185+
186+
The `Carbon` class extends the popular Carbon library with additional convenience methods.
187+
188+
### Creating Instances
189+
190+
```php
191+
use Farzai\Support\Carbon;
192+
use function Farzai\Support\now;
193+
194+
// Get current date/time
195+
$now = now();
196+
// or
197+
$now = Carbon::now();
198+
199+
// With timezone
200+
$now = now('America/New_York');
201+
$now = Carbon::now('UTC');
202+
203+
// From timestamp
204+
$date = Carbon::fromTimestamp(1609459200);
205+
```
206+
207+
### Date Checking
208+
209+
```php
210+
use Farzai\Support\Carbon;
211+
212+
$today = Carbon::now();
213+
$yesterday = Carbon::yesterday();
214+
$tomorrow = Carbon::tomorrow();
215+
216+
// Check if today
217+
$today->isToday(); // Returns: true
218+
$yesterday->isToday(); // Returns: false
219+
220+
// Check if past
221+
$yesterday->isPast(); // Returns: true
222+
$tomorrow->isPast(); // Returns: false
223+
224+
// Check if future
225+
$tomorrow->isFuture(); // Returns: true
226+
$yesterday->isFuture(); // Returns: false
227+
228+
// Check if between dates
229+
$today->isBetweenDates($yesterday, $tomorrow); // Returns: true
230+
```
231+
232+
### Date Formatting
233+
234+
```php
235+
use Farzai\Support\Carbon;
236+
237+
$date = Carbon::now();
238+
239+
// Format as date string
240+
$date->toDateString(); // Returns: '2024-03-18'
241+
242+
// Format as time string
243+
$date->toTimeString(); // Returns: '14:30:45'
244+
245+
// Format as datetime string
246+
$date->toDateTimeString(); // Returns: '2024-03-18 14:30:45'
247+
```
248+
249+
### Day Boundaries
250+
251+
```php
252+
use Farzai\Support\Carbon;
253+
254+
$date = Carbon::now();
255+
256+
// Start of day
257+
$start = $date->startOfDay(); // Returns: today at 00:00:00
258+
259+
// End of day
260+
$end = $date->endOfDay(); // Returns: today at 23:59:59
261+
```
262+
263+
### Date Differences
264+
265+
```php
266+
use Farzai\Support\Carbon;
267+
268+
$today = Carbon::now();
269+
$yesterday = Carbon::yesterday();
270+
271+
// Absolute difference in days
272+
$today->diffInDaysAbsolute($yesterday); // Returns: 1
273+
```
274+
275+
## Helper Functions
276+
277+
Global helper functions in the `Farzai\Support` namespace.
278+
279+
### tap()
280+
281+
Execute a callback on a value and return the value:
282+
283+
```php
284+
use function Farzai\Support\tap;
285+
286+
// With callback
287+
$user = tap($user, function ($u) {
288+
$u->update(['last_login' => now()]);
289+
});
290+
// Returns $user after updating
291+
292+
// Without callback (higher-order proxy)
293+
$user = tap($user)
294+
->update(['last_login' => now()])
295+
->save();
296+
// Chains methods but returns $user
297+
```
298+
299+
### now()
300+
301+
Get the current date/time:
302+
303+
```php
304+
use function Farzai\Support\now;
305+
306+
$current = now(); // Returns: Carbon instance
307+
$ny = now('America/New_York'); // Returns: Carbon instance in NY timezone
308+
```
309+
310+
### class_basename()
311+
312+
Get the class name without namespace:
313+
314+
```php
315+
use function Farzai\Support\class_basename;
316+
317+
class_basename('App\Models\User'); // Returns: 'User'
318+
class_basename(new \App\Models\User); // Returns: 'User'
319+
```
320+
321+
## Development
322+
323+
### Running Tests
324+
325+
```php
20326
composer test
21327
```
22328

329+
### Running Tests with Coverage
330+
331+
```bash
332+
composer test-coverage
333+
```
334+
335+
### Code Formatting
336+
337+
```bash
338+
composer format
339+
```
340+
341+
### Static Analysis
342+
343+
```bash
344+
composer analyze
345+
```
346+
347+
### Run All Checks
348+
349+
```bash
350+
composer check
351+
```
352+
23353
## Changelog
24354

25355
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

composer.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
"nesbot/carbon": "^2.72.2|^3.0"
1919
},
2020
"require-dev": {
21-
"pestphp/pest": "^1.20",
21+
"pestphp/pest": "^1.20 || ^2.0",
2222
"laravel/pint": "^1.2",
23-
"spatie/ray": "^1.28"
23+
"spatie/ray": "^1.28",
24+
"phpstan/phpstan": "^1.10",
25+
"phpstan/extension-installer": "^1.3"
2426
},
2527
"autoload": {
2628
"psr-4": {
@@ -38,7 +40,14 @@
3840
"scripts": {
3941
"test": "vendor/bin/pest",
4042
"test-coverage": "vendor/bin/pest --coverage",
41-
"format": "vendor/bin/pint"
43+
"format": "vendor/bin/pint",
44+
"analyze": "vendor/bin/phpstan analyse",
45+
"analyze-baseline": "vendor/bin/phpstan analyse --generate-baseline",
46+
"check": [
47+
"@format",
48+
"@analyze",
49+
"@test"
50+
]
4251
},
4352
"config": {
4453
"sort-packages": true,

0 commit comments

Comments
 (0)