├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── psalm.xml ├── src └── SternTrait.php └── tests ├── autoload.php ├── phpunit └── WeakSternTest.php └── test-classes └── Weak.php /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | old: 7 | name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} 8 | runs-on: ${{ matrix.operating-system }} 9 | strategy: 10 | matrix: 11 | operating-system: ['ubuntu-18.04'] 12 | php-versions: ['7.0'] 13 | phpunit-versions: ['6.5.14'] 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | 18 | - name: Setup PHP 19 | uses: shivammathur/setup-php@v2 20 | with: 21 | php-version: ${{ matrix.php-versions }} 22 | extensions: mbstring, intl 23 | ini-values: post_max_size=256M, max_execution_time=180 24 | tools: psalm, phpunit:${{ matrix.phpunit-versions }} 25 | 26 | - name: Fix permissions 27 | run: sudo chmod -R 0777 . 28 | 29 | - name: Install dependencies 30 | run: composer self-update --1; composer install 31 | 32 | - name: PHPUnit tests 33 | uses: php-actions/phpunit@v2 34 | with: 35 | memory_limit: 256M 36 | 37 | moderate: 38 | name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} 39 | runs-on: ${{ matrix.operating-system }} 40 | strategy: 41 | matrix: 42 | operating-system: ['ubuntu-latest'] 43 | php-versions: ['7.1', '7.2', '7.3'] 44 | phpunit-versions: ['latest'] 45 | steps: 46 | - name: Checkout 47 | uses: actions/checkout@v2 48 | 49 | - name: Setup PHP 50 | uses: shivammathur/setup-php@v2 51 | with: 52 | php-version: ${{ matrix.php-versions }} 53 | extensions: mbstring, intl, sodium 54 | ini-values: post_max_size=256M, max_execution_time=180 55 | tools: psalm, phpunit:${{ matrix.phpunit-versions }} 56 | 57 | - name: Fix permissions 58 | run: sudo chmod -R 0777 . 59 | 60 | - name: Install dependencies 61 | run: composer install 62 | 63 | - name: PHPUnit tests 64 | uses: php-actions/phpunit@v2 65 | timeout-minutes: 30 66 | with: 67 | memory_limit: 256M 68 | 69 | modern: 70 | name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} 71 | runs-on: ${{ matrix.operating-system }} 72 | strategy: 73 | matrix: 74 | operating-system: ['ubuntu-latest'] 75 | php-versions: ['7.4', '8.0', '8.1'] 76 | phpunit-versions: ['latest'] 77 | steps: 78 | - name: Checkout 79 | uses: actions/checkout@v2 80 | 81 | - name: Setup PHP 82 | uses: shivammathur/setup-php@v2 83 | with: 84 | php-version: ${{ matrix.php-versions }} 85 | extensions: mbstring, intl, sodium 86 | ini-values: post_max_size=256M, max_execution_time=180 87 | tools: psalm, phpunit:${{ matrix.phpunit-versions }} 88 | 89 | - name: Fix permissions 90 | run: sudo chmod -R 0777 . 91 | 92 | - name: Install dependencies 93 | run: composer install 94 | 95 | - name: PHPUnit tests 96 | uses: php-actions/phpunit@v2 97 | timeout-minutes: 30 98 | with: 99 | memory_limit: 256M 100 | 101 | - name: Install Psalm 102 | run: composer require --dev vimeo/psalm:^4 103 | 104 | - name: Static Analysis 105 | run: vendor/bin/psalm 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Paragon Initiative Enterprises 4 | 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: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stern 2 | 3 | [![Build Status](https://github.com/paragonie/stern/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/stern/actions) 4 | [![Latest Stable Version](https://poser.pugx.org/paragonie/stern/v/stable)](https://packagist.org/packages/paragonie/stern) 5 | [![Latest Unstable Version](https://poser.pugx.org/paragonie/stern/v/unstable)](https://packagist.org/packages/paragonie/stern) 6 | [![License](https://poser.pugx.org/paragonie/stern/license)](https://packagist.org/packages/paragonie/stern) 7 | 8 | Stern lets you built type-safe PHP projects, even if your project's users aren't writing type-safe code. 9 | 10 | **Requires PHP 7+** 11 | 12 | ## Usage 13 | 14 | Using Stern is simply: 15 | 16 | 1. Make your class use the `SternTrait`. 17 | 2. Rename your methods from `whateverName` to `strictWhateverName`. 18 | 3. Enjoy strict-typing whether your users like it or not. 19 | 20 | ## Example 21 | 22 | ```diff 23 | 2 | 12 | 13 | 14 | ./src 15 | 16 | 17 | 18 | 19 | ./tests/phpunit 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/SternTrait.php: -------------------------------------------------------------------------------- 1 | {'strict' . $name}(...$arguments); 21 | } 22 | 23 | throw new \Error( 24 | \sprintf('Destination proxy method %s not found on class %s', 'strict' . $name, \get_class($this)) 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/autoload.php: -------------------------------------------------------------------------------- 1 | assertSame(true, $weak->weakBool(true)); 15 | $this->assertSame(false, $weak->weakBool(false)); 16 | try { 17 | $weak->weakBool(null); 18 | $this->fail('Expected a TypeError'); 19 | } catch (Error $ex) { 20 | $this->assertTrue($ex instanceof TypeError); 21 | } 22 | try { 23 | $weak->weakBool(0); 24 | $this->fail('Expected a TypeError'); 25 | } catch (Error $ex) { 26 | $this->assertTrue($ex instanceof TypeError); 27 | } 28 | } 29 | 30 | public function testWeakFloat() 31 | { 32 | $weak = new Weak(); 33 | $this->assertSame(123.45, $weak->weakFloat(123.45)); 34 | $this->assertSame(12345.0, $weak->weakFloat(12345.0)); 35 | 36 | try { 37 | $weak->weakFloat('123.44'); 38 | $this->fail('Expected a TypeError'); 39 | } catch (Error $ex) { 40 | $this->assertTrue($ex instanceof TypeError); 41 | } 42 | } 43 | 44 | public function testWeakInt() 45 | { 46 | $weak = new Weak(); 47 | $this->assertSame(12345, $weak->weakInt(12344)); 48 | 49 | try { 50 | $weak->weakInt('12344'); 51 | $this->fail('Expected a TypeError'); 52 | } catch (Error $ex) { 53 | $this->assertTrue($ex instanceof TypeError); 54 | } 55 | } 56 | 57 | public function testWeakString() 58 | { 59 | $weak = new Weak(); 60 | $this->assertSame('nccyr', $weak->weakString('apple')); 61 | $this->assertSame('NCCYR', $weak->weakString('APPLE')); 62 | $this->assertSame('12345', $weak->weakString('12345')); 63 | 64 | try { 65 | $weak->weakString(12345); 66 | $this->fail('Expected a TypeError'); 67 | } catch (Error $ex) { 68 | $this->assertTrue($ex instanceof TypeError); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/test-classes/Weak.php: -------------------------------------------------------------------------------- 1 |