PHPackages                             memran/marwa-support - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. memran/marwa-support

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

memran/marwa-support
====================

Framework-agnostic PHP support library with typed helpers for strings, arrays, files, objects, validation, and security primitives

v1.3.1(2mo ago)11.2k7MITPHPPHP ^8.2CI passing

Since Aug 16Pushed 2mo agoCompare

[ Source](https://github.com/memran/marwa-support)[ Packagist](https://packagist.org/packages/memran/marwa-support)[ RSS](/packages/memran-marwa-support/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (8)Versions (8)Used By (7)

Marwa Support
=============

[](#marwa-support)

[![Latest Version](https://camo.githubusercontent.com/ee349b72c647e08e9d642f4ba1406ece3de8737aa85e49196daa68fbba766805/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d656d72616e2f6d617277612d737570706f72742e737667)](https://packagist.org/packages/memran/marwa-support)[![Total Downloads](https://camo.githubusercontent.com/9fcb08dfc54ff1f3eb8099c5d132dea2f15276a78df04990a784d5169841bfa5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d656d72616e2f6d617277612d737570706f72742e737667)](https://packagist.org/packages/memran/marwa-support)[![License](https://camo.githubusercontent.com/24940140a08af34fe9fbd644ff21faaef384a11d83e02403db699fdfd1f624cd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d656d72616e2f6d617277612d737570706f72742e737667)](https://packagist.org/packages/memran/marwa-support)[![PHP Version](https://camo.githubusercontent.com/3f669412036e6f91c64a4b5361aeeaa702cbd8cf25a1e1082f474a00f0af7a34/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6d656d72616e2f6d617277612d737570706f72742e737667)](https://packagist.org/packages/memran/marwa-support)[![CI](https://github.com/memran/marwa-support/actions/workflows/ci.yml/badge.svg)](https://github.com/memran/marwa-support/actions/workflows/ci.yml)[![Coverage](https://camo.githubusercontent.com/292d119717713da21f8d40dad901d09bce0ae32ea4e3c768b3e063d8cfa7f97b/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f6d656d72616e2f6d617277612d737570706f72742e737667)](https://codecov.io/gh/memran/marwa-support)[![PHPStan](https://camo.githubusercontent.com/0729e562e10fac943b16dbb271b4af26488f779a33fc82cc3eef1e37a432c0b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230352d627269676874677265656e2e737667)](https://phpstan.org/)

Framework-agnostic PHP support utilities for common string, array, file, object, validation, HTML, and security tasks. The package is designed for library and application code that needs small, composable helpers with strict typing and predictable behavior.

Requirements
------------

[](#requirements)

- PHP 8.2 or newer
- Extensions: `json`, `mbstring`, `openssl`

Installation
------------

[](#installation)

```
composer require memran/marwa-support
```

For local development:

```
composer install
```

API Reference
-------------

[](#api-reference)

### Strings (`Str`)

[](#strings-str)

String manipulation utilities with full Unicode support.

```
use Marwa\Support\Str;

// Case conversion
Str::lower('HELLO');                    // "hello"
Str::upper('hello');                    // "HELLO"
Str::title('hello world');              // "Hello World"

// Case styles
Str::camel('hello_world');              // "helloWorld"
Str::studly('hello_world');             // "HelloWorld"
Str::snake('helloWorld');               // "hello_world"
Str::snake('HelloWorld', '-');          // "hello-world"

// Slug generation
Str::slug('Hello World!');              // "hello-world"
Str::slug('Secure Helper Library');    // "secure-helper-library"

// String checks
Str::contains('hello world', 'world');  // true
Str::contains('hello world', ['foo', 'world']); // true
Str::startsWith('hello', 'hel');        // true
Str::endsWith('hello', 'llo');         // true
Str::is('*.php', 'controller.php');    // true
Str::is('test*', 'testing');           // true

// String extraction
Str::between('hello[world]', '[', ']'); // "world"
Str::substring('hello', 1, 3);         // "ell"
Str::limit('hello world', 5);          // "hello..."
Str::limit('hello world', 5, '…');     // "hello…"

// HTML handling
Str::escape('');               // "&lt;script&gt;"
Str::stripTags('hello');       // "hello"
Str::hash('password');                // "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"

// Misc
Str::random(16);                       // "aB3kL9mNpQxR2tYv"
Str::wordCount('hello world');        // 2
Str::pad('hello', 10, '-', STR_PAD_BOTH); // "--hello---"
Str::repeat('ab', 3);                  // "ababab"
Str::reverse('hello');                 // "olleh"
Str::toBytes('10MB');                 // 10485760
```

### Arrays (`Arr`)

[](#arrays-arr)

Array manipulation with dot notation support.

```
use Marwa\Support\Arr;

// Dot notation access
$data = ['user' => ['name' => 'John', 'email' => 'john@example.com']];
Arr::get($data, 'user.name');                          // "John"
Arr::get($data, 'user.phone', 'N/A');                  // "N/A"
Arr::has($data, 'user.email');                         // true
Arr::has($data, 'user.phone');                         // false

// Dot notation set
$array = [];
Arr::set($array, 'user.name', 'John');                 // ['user' => ['name' => 'John']]
Arr::set($array, 'items.0.name', 'Item 1');           // ['user' => [...], 'items' => [['name' => 'Item 1']]]

// Flatten to dot notation
Arr::dot(['a' => ['b' => 1]]);                         // ['a.b' => 1]

// Find elements
Arr::first([1, 2, 3]);                                 // 1
Arr::first([1, 2, 3], fn($v) => $v > 1);              // 2
Arr::last([1, 2, 3]);                                 // 3
Arr::last([1, 2, 3], fn($v) => $v < 3);               // 2

// Transform
Arr::pluck([['id' => 1, 'name' => 'a'], ['id' => 2, 'name' => 'b']], 'name');
// ['a', 'b']
Arr::pluck([['id' => 1, 'name' => 'a'], ['id' => 2, 'name' => 'b']], 'name', 'id');
// [1 => 'a', 2 => 'b']
Arr::where([1, 2, 3, 4], fn($v) => $v > 2);           // [3, 4]
Arr::only(['a' => 1, 'b' => 2, 'c' => 3], ['a', 'c']); // ['a' => 1, 'c' => 3]
Arr::except(['a' => 1, 'b' => 2, 'c' => 3], ['b']);   // ['a' => 1, 'c' => 3]
```

### Files (`File`)

[](#files-file)

Atomic file operations with validation and directory creation.

```
use Marwa\Support\File;

// Write/Read
File::put(__DIR__ . '/data.json', ['key' => 'value']); // Returns byte count
File::get(__DIR__ . '/data.json');                     // Returns file contents

// Append
File::append(__DIR__ . '/log.txt', "New log entry\n");

// Delete
File::delete(__DIR__ . '/old.txt');                    // Returns bool

// Directory operations
File::makeDirectory(__DIR__ . '/newfolder');

// File info
File::exists(__DIR__ . '/file.txt');                   // bool
File::size(__DIR__ . '/file.txt');                     // int (bytes)
File::lastModified(__DIR__ . '/file.txt');             // int (timestamp)

// Copy/Move
File::copy('source.txt', 'dest.txt');
File::move('old.txt', 'new.txt');
```

### JSON (`Json`)

[](#json-json)

JSON encode/decode with error handling and utilities.

```
use Marwa\Support\Json;

// Encode/Decode
Json::encode(['foo' => 'bar']);                    // '{"foo":"bar"}'
Json::decode('{"foo":"bar"}');                     // ['foo' => 'bar']
Json::decode('{"foo":"bar"}', false);              // stdClass object

// Validation
Json::isValid('{"foo":"bar"}');                    // true
Json::isValid('not json');                         // false

// Pretty print
Json::pretty(['foo' => 'bar']);
// {
//     "foo": "bar"
// }

// Minify
Json::minify('{"foo": "bar"}');                    // '{"foo":"bar"}'

// Dot notation access
$json = '{"user":{"name":"John"}}';
Json::get($json, 'user.name');                     // "John"
Json::has($json, 'user.name');                     // true

// Array conversion
Json::fromArray(['foo' => 'bar']);                 // '{"foo":"bar"}'
Json::toArray('{"foo":"bar"}');                    // ['foo' => 'bar']
```

### URLs (`Url`)

[](#urls-url)

URL parsing, building, and manipulation.

```
use Marwa\Support\Url;

// Parse URL
$components = Url::parse('https://example.com:8080/path?query=value#fragment');
// ['scheme' => 'https', 'host' => 'example.com', 'port' => 8080, 'path' => '/path', 'query' => 'query=value', 'fragment' => 'fragment']

// Build URL
Url::build(['scheme' => 'https', 'host' => 'example.com', 'path' => '/path']);
// "https://example.com/path"

// Query string
Url::query('https://example.com?foo=bar&baz=qux'); // ['foo' => 'bar', 'baz' => 'qux']
Url::withQuery('https://example.com', ['foo' => 'bar']); // Adds/updates query params
Url::withoutQuery('https://example.com?foo=bar', 'foo'); // Removes query param
Url::getQuery('https://example.com?key=value', 'key'); // "value"

// URL parts
Url::scheme('https://example.com');               // "https"
Url::host('https://example.com/path');            // "example.com"
Url::port('https://example.com:8080');            // 8080
Url::path('https://example.com/path/to');          // "/path/to"
Url::fragment('https://example.com#section');      // "section"
Url::domain('https://www.example.com');           // "example.com"

// Utilities
Url::isAbsolute('https://example.com');            // true
Url::isAbsolute('/path');                          // false
Url::fullDomain('https://example.com:8080/path'); // "https://example.com:8080"
```

### Numbers (`Number`)

[](#numbers-number)

Number formatting, currency, percentage, and conversions.

```
use Marwa\Support\Number;

// Basic formatting
Number::format(1234);                              // "1,234"
Number::format(1234.567, 2);                       // "1,234.57"

// Currency (uses NumberFormatter when available)
Number::currency(1234.56);                         // "$1,234.56"

// Percentage
Number::percentage(0.5);                           // "50%"
Number::percentage(0.333, 1);                      // "33.3%"

// Ordinals
Number::ordinal(1);                                // "1st"
Number::ordinal(22);                              // "22nd"

// Compact notation
Number::compact(1500);                             // "1.5K"
Number::compact(2000000);                          // "2M"
Number::compact(1000000000);                       // "1B"

// Bytes
Number::bytes(1024);                              // "1 KB"
Number::bytes(1572864, 1);                         // "1.5 MB"

// Rounding
Number::round(1.234, 2);                          // 1.23
Number::ceil(4.2);                                 // 5
Number::floor(4.8);                                // 4

// Clamping
Number::clamp(10, 0, 5);                          // 5
Number::between(3, 1, 5);                         // true

// Roman numerals
Number::roman(1994);                               // "MCMXCIV"
```

### Security (`Security`, `Crypt`, `Hash`, `Random`, `Sanitizer`, `XSS`, `CSRF`, `Validator`)

[](#security-security-crypt-hash-random-sanitizer-xss-csrf-validator)

Comprehensive security utilities.

```
use Marwa\Support\Security;
use Marwa\Support\Crypt;
use Marwa\Support\Hash;
use Marwa\Support\Random;
use Marwa\Support\Sanitizer;
use Marwa\Support\XSS;
use Marwa\Support\CSRF;
use Marwa\Support\Validator;

// Encryption/Decryption (AES-256-GCM)
$encrypted = Crypt::encrypt('secret data', 'my-key');
$decrypted = Crypt::decrypt($encrypted, 'my-key');

// Password hashing
$hash = Hash::make('password');
Hash::verify('password', $hash);                       // true
Hash::needsRehash($hash);                             // bool

// Random generation
Random::bytes(32);                                    // Raw bytes
Random::string(16);                                   // Alphanumeric string
Random::string(16, 'alpha');                          // Letters only
Random::string(16, 'hex');                            // Hex characters
Random::uuid();                                       // v4 UUID

// Security facade
Security::encrypt($data, $key);
Security::decrypt($data, $key);
Security::hash('password');
Security::verifyHash('password', $hash);
Security::randomBytes(32);
Security::randomString(16);
Security::uuid();
Security::sanitize($input, 'email');
Security::safeFileName('file name.exe');
Security::validate('test@example.com', 'email');
Security::isMalicious('alert(1)'); // true
Security::csrfToken();
Security::verifyCsrf($token);
Security::xssClean($input);
Security::hashEquals($known, $user);

// Sanitization
Sanitizer::clean('alert(1)', 'string');
Sanitizer::clean('test@example.com', 'email');
Sanitizer::clean('http://example.com', 'url');
Sanitizer::clean('123.45', 'float');
Sanitizer::filename('test file.php');                // "test_file.php"

// XSS Cleaning
XSS::clean('alert(1)safe');
// Output: "&lt;script&gt;alert(1)&lt;/script&gt;safe"

// CSRF Tokens (requires session)
$token = CSRF::token();
CSRF::verify($token);                                 // true/false

// Validation
Validator::check('test@example.com', 'email');       // true
Validator::check('http://example.com', 'url');       // true
Validator::check('192.168.1.1', 'ip');                // true
Validator::check('00:1B:44:11:3A:B7', 'mac');        // true
Validator::isMalicious('alert(1)'); // true
```

### Validation (`Validation`)

[](#validation-validation)

Full-featured validation with pipe syntax. Uses the new rule-based validation system internally.

```
use Marwa\Support\Validation;

$validator = Validation::make(
    [
        'name' => 'John',
        'email' => 'john@example.com',
        'age' => 25,
        'password' => 'secret123',
        'password_confirmation' => 'secret123',
        'role' => 'admin',
    ],
    [
        'name' => 'required|min:2|max:50',
        'email' => 'required|email',
        'age' => 'numeric|min:18|max:150',
        'password' => 'required|string|min:6',
        'password_confirmation' => 'same:password',
        'role' => 'in:admin,user,guest',
    ]
);

if ($validator->fails()) {
    print_r($validator->errors());
}

// Custom messages
$validator = Validation::make(
    ['email' => 'invalid'],
    ['email' => 'email'],
    ['email.email' => 'Please enter a valid email address']
);

// Custom rules via extend()
$validator = Validation::make(['code' => 'ABC123'], ['code' => 'required']);
$validator->extend('uppercase', fn($field, $value) => strtoupper($value) === $value);
$validator->addError('code', 'Code must be uppercase');
```

### Advanced Validation (`Marwa\Support\Validation\RequestValidator`)

[](#advanced-validation-marwasupportvalidationrequestvalidator)

For complex validation scenarios, use the full-featured rule-based validation system directly.

```
use Marwa\Support\Validation\RequestValidator;
use Marwa\Support\Validation\ValidationException;

$validator = new RequestValidator();

// Validate array input
$validated = $validator->validateInput(
    ['name' => 'John', 'email' => 'john@example.com'],
    ['name' => 'required|min:2|max:50', 'email' => 'required|email']
);

// With PSR-7 ServerRequest
try {
    $validated = $validator->validateRequest($request, $rules);
} catch (ValidationException $e) {
    $errors = $e->getErrors();    // All errors
    $firstErrors = $e->getFirstErrors(); // First error per field
}

// Built-in rules:
// - Type: required, present, filled, string, integer, numeric, boolean, array
// - Format: email, url, ip, mac
// - Size: min:value, max:value, between:min,max
// - Content: in:value1,value2, same:field, confirmed, date, date_format:Y-m-d, regex:pattern
// - Special: accepted, declined

// Custom field attributes
$validated = $validator->validateInput(
    $input,
    $rules,
    [],           // custom messages
    ['name' => 'Full Name']  // attribute labels
);
```

### Validation Rules

[](#validation-rules)

Individual rule classes for custom validation logic.

```
use Marwa\Support\Validation\Rules\RequiredRule;
use Marwa\Support\Validation\Rules\EmailRule;
use Marwa\Support\Validation\Rules\MinRule;

// Use rules directly
$rule = new RequiredRule();
$isValid = $rule->validate($value, ['input' => $data, 'field' => 'email']);
$message = $rule->message('email', []);

// Register custom rules
$registry = new RuleRegistry();
$registry->register('custom', MyCustomRule::class);

// Create custom rule
use Marwa\Support\Validation\AbstractRule;

class UppercaseRule extends AbstractRule
{
    public function name(): string
    {
        return 'uppercase';
    }

    public function validate(mixed $value, array $context): bool
    {
        return $value === strtoupper($value);
    }

    public function message(string $field, array $attributes): string
    {
        return $this->formatMessage('The :attribute must be uppercase.', $field, $attributes);
    }
}
```

### Helpers (`Helper`)

[](#helpers-helper)

Functional programming utilities.

```
use Marwa\Support\Helper;

// Tap - execute callback without changing value
$result = Helper::tap('hello', fn($v) => strtoupper($v)); // Returns "hello"

// Pipe - chain transformations
$result = Helper::pipe(5, [
    fn($v) => $v * 2,
    fn($v) => $v + 1,
]); // 11

// With - apply callback to value, return default on null
Helper::with(null, fn($v) => strtoupper($v), 'default'); // "default"
Helper::with('hello', fn($v) => strtoupper($v));         // "HELLO"

// Debugging
Helper::dump($var);  // Returns var_dump output as string
Helper::dd($var);    // Dumps and exits

// Retry with backoff
$result = Helper::retry(3, fn() => someApiCall(), 100); // retries 3 times, 100ms sleep

// Data get (nested access)
Helper::dataGet(['user' => ['name' => 'John']], 'user.name'); // "John"
Helper::dataGet(['items' => [['a' => 1], ['a' => 2]]], 'items.*.a'); // [1, 2]

// Value - unwrap closures or return as-is
Helper::value('hello');                                      // "hello"
Helper::value(fn() => 'computed');                           // "computed"

// Type checking
Helper::empty('');           // true
Helper::empty('0');          // false
Helper::typeOf($var);        // "string", "array", "classname", etc.

// Functional
$memoized = Helper::memoize(fn($n) => expensive($n));
$curried = Helper::curry(fn($a, $b, $c) => $a + $b + $c);

// Array operations
Helper::groupBy([['role' => 'admin'], ['role' => 'user']], 'role');
// ['admin' => [[...]], 'user' => [[...]]]
Helper::keyBy([['id' => 1], ['id' => 2]], 'id');
// [1 => [...], 2 => [...]]

// Math
Helper::percentage(25, 100);      // 25.0
Helper::mapRange(50, 0, 100, 0, 1); // 0.5

// Object
Helper::deepClone($object);
Helper::implements($object, 'JsonSerializable');

// Misc
Helper::uuid();                    // UUID v4
Helper::truncate('long string', 10); // "long strin..."
Helper::measure(fn() => sleep(1));   // Returns execution time in ms
Helper::memoryUsage(memory_get_usage()); // "1.5 MB"
```

### Objects (`Obj`)

[](#objects-obj)

Object manipulation utilities.

```
use Marwa\Support\Obj;

class User {
    public string $name = 'John';
    public array $data = [];
}

$user = new User();

// Convert to array
Obj::toArray($user);    // ['name' => 'John', 'data' => []]

// Fill properties
Obj::fill($user, ['name' => 'Jane', 'age' => 30]);

// Get nested property
$obj = (object) ['user' => ['name' => 'John']];
Obj::get($obj, 'user.name'); // "John"

// Check property exists
Obj::has($obj, 'user.name'); // true

// Convert to JSON
Obj::toJson($user);    // '{"name":"John","data":{}}'

// Other
Obj::clone($object);
Obj::className($object);    // "User"
Obj::properties($object);   // ['name' => 'John', ...]
```

### HTML (`Html`)

[](#html-html)

HTML generation and manipulation.

```
use Marwa\Support\Html;

// Element generation
Html::element('div', ['class' => 'container'], 'Content');
// Content

Html::element('img', ['src' => 'image.jpg', 'alt' => 'Photo']);
//

// Common tags
Html::link('https://example.com', 'Visit Site', ['class' => 'btn']);
Html::image('photo.jpg', 'A photo');
Html::script('app.js');
Html::style('style.css');
Html::meta('description', 'My website');
Html::form('/submit', 'POST', ['class' => 'form']);

// Form elements
Html::input('text', 'name', 'John', ['class' => 'input']);
Html::input('email', 'email', 'test@example.com');
Html::select('country', ['us' => 'USA', 'uk' => 'UK'], 'us');
Html::select('color', ['red' => 'Red', 'blue' => 'Blue'], null, ['multiple' => true]);

// HTML array structure
$structure = [
    'div' => [
        'attributes' => ['class' => 'card'],
        'content' => [
            'h2' => 'Title',
            'p' => 'Description'
        ]
    ]
];
Html::fromArray($structure);

// Utilities
Html::escape('');                 // "&lt;script&gt;"
Html::decode('&lt;script&gt;');          // ""
Html::text('Hello');              // "Hello"
Html::minify('   ');          // ""
Html::doctype();                         // ""

// Document generation
Html::document('My Page', 'Hello', ['description' => 'Page description']);

// Extract elements
$html = 'Content';
Html::extract($html, '.item');
// Returns array of matched elements with html, text, and attributes
```

### Dates (`Date`)

[](#dates-date)

Date and time utilities.

```
use Marwa\Support\Date;

// Formatting
Date::format('2024-01-15');                       // "2024-01-15 00:00:00"
Date::format('2024-01-15', 'Y-m-d');             // "2024-01-15"
Date::format(1705276800, 'F j, Y');              // "January 15, 2024"

// Date arithmetic
Date::addDays('2024-01-15', 10);                 // DateTime object
Date::subDays('2024-01-15', 5);                  // DateTime object

// Comparison
Date::isAfter('2024-01-15', '2024-01-10');       // true
Date::isBefore('2024-01-15', '2024-01-20');     // true
Date::diffInDays('2024-01-20', '2024-01-15');   // 5

// Current time
Date::now();                                     // DateTime object
Date::timestamp();                               // int (current timestamp)
```

### Finder (`Finder`)

[](#finder-finder)

File system searching with fluent API.

```
use Marwa\Support\Finder;

// Find files
$files = Finder::in(__DIR__ . '/src')
    ->files()
    ->name('/\.php$/');

// Find directories
$dirs = Finder::in(__DIR__ . '/src')
    ->directories();

// Filter by name pattern
$phpFiles = Finder::in(__DIR__)
    ->name('\.php$')
    ->files();

// Filter by size
$largeFiles = Finder::in(__DIR__)
    ->files()
    ->size('>', 1024 * 1024); // Files > 1MB

// Chain with Collection methods
$results = Finder::in(__DIR__ . '/src')
    ->files()
    ->name('/\.php$/')
    ->filter(fn($f) => $f->getSize() > 1000)
    ->map(fn($f) => $f->getFilename())
    ->all();
```

### Collection (`Collection`)

[](#collection-collection)

Array-backed collection with chainable methods.

```
use Marwa\Support\Collection;

// Create
$collection = Collection::make([1, 2, 3, 4, 5]);
$collection = new Collection(['a' => 1, 'b' => 2]);

// Access
$collection->all();                // [1, 2, 3, 4, 5]
$collection->get('a', 'default');  // 1
$collection->first();             // 1
$collection->last();               // 5

// Modification
$collection->put('c', 3);
$collection->push(6);
$collection->first(fn($v) => $v > 2); // Returns first matching

// Transform
$collection->map(fn($v) => $v * 2); // Collection [2, 4, 6, 8, 10]
$collection->filter(fn($v) => $v % 2 === 0); // Collection [2, 4]
$collection->pluck('name');       // Collection of field values
$collection->pluck('name', 'id'); // Collection keyed by field
$collection->keys();              // Collection ['a', 'b', 'c']
$collection->values();            // Collection [1, 2, 3]
$collection->each(fn($v, $k) => print "$k: $v\n");

// Sorting
$sorted = $collection->sortBy(fn($v) => $v, true); // descending

// Grouping
$grouped = Collection::make([
    ['role' => 'admin', 'name' => 'Alice'],
    ['role' => 'user', 'name' => 'Bob'],
])->groupBy('role');

// Check
$collection->count();         // 5
$collection->isEmpty();       // false
$collection->isNotEmpty();    // true

// Output
$collection->toArray();
$collection->toJson();
(string) $collection; // auto-converts to JSON
```

Configuration
-------------

[](#configuration)

The library is mostly configuration-free. Pass secrets such as encryption keys from your application configuration or environment, not from hard-coded strings. For CSRF helpers, call them only in applications that already manage PHP sessions safely.

Testing
-------

[](#testing)

```
composer test
composer test:coverage
```

Static Analysis
---------------

[](#static-analysis)

```
composer analyse
composer lint
composer fix
```

`phpstan.neon.dist` runs analysis on `src/` at level 5. `.php-cs-fixer.dist.php` enforces PSR-12-style formatting with strict typing rules.

CI/CD
-----

[](#cicd)

GitHub Actions runs Composer validation, coding standards, PHPStan, and PHPUnit on PHP 8.2, 8.3, and 8.4 through [`.github/workflows/ci.yml`](./.github/workflows/ci.yml).

Contributing
------------

[](#contributing)

1. Install dependencies with `composer install`.
2. Run `composer ci` before opening a pull request.
3. Add or update PHPUnit coverage for behavior changes.
4. Keep commits focused and describe the behavioral impact in the PR.

Repository-specific contributor guidance is available in [`AGENTS.md`](./AGENTS.md).

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance85

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~40 days

Recently: every ~60 days

Total

7

Last Release

77d ago

PHP version history (2 changes)v1.0.0PHP ^8.0

v1.2.1PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/8cf906a31a250a940314fe42f8a18f449647bfe18095457350ff0081cf8dd3c2?d=identicon)[memran](/maintainers/memran)

---

Top Contributors

[![memran](https://avatars.githubusercontent.com/u/7415198?v=4)](https://github.com/memran "memran (26 commits)")

---

Tags

arraycollectionfilejsonmarwaphpphpphp82securitystringssupport-libraryvalidationphpvalidationhelperssecurityutilities

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/memran-marwa-support/health.svg)

```
[![Health](https://phpackages.com/badges/memran-marwa-support/health.svg)](https://phpackages.com/packages/memran-marwa-support)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[aporat/store-receipt-validator

PHP receipt validator for Apple App Store and Amazon Appstore

6544.0M13](/packages/aporat-store-receipt-validator)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35789.4k2](/packages/telnyx-telnyx-php)[progsmile/request-validator

Simple PHP Request Validator

37114.5k1](/packages/progsmile-request-validator)[andreas-glaser/php-helpers

A comprehensive collection of PHP utility functions for array manipulation, string operations, date handling, HTML generation, form building, validation, and more. Modern PHP 8.2+ library with full type safety.

1388.1k2](/packages/andreas-glaser-php-helpers)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
