├── .gitignore ├── .php_cs.dist ├── .travis.yml ├── LICENSE ├── README.md ├── check_trailing_spaces.sh ├── composer.json ├── dev-tools ├── .gitignore └── composer.json ├── phpmd.xml ├── phpunit.xml.dist ├── src └── AccessibleObject.php └── tests ├── AccessibleObjectTest.php └── Fixtures └── AccessibleObjectTest └── DummyClass.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.php_cs 2 | /.php_cs.cache 3 | /.phpunit.result.cache 4 | /composer.lock 5 | /phpunit.xml 6 | /vendor/ 7 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | 7 | Dariusz Rumiński 8 | 9 | This source file is subject to the MIT license that is bundled 10 | with this source code in the file LICENSE. 11 | EOF; 12 | 13 | $config = PhpCsFixer\Config::create() 14 | ->setRiskyAllowed(true) 15 | ->setRules([ 16 | '@PHP56Migration' => true, 17 | '@Symfony' => true, 18 | '@Symfony:risky' => true, 19 | 'align_multiline_comment' => true, 20 | 'array_syntax' => ['syntax' => 'long'], 21 | 'blank_line_before_statement' => true, 22 | 'combine_consecutive_unsets' => true, 23 | // one should use PHPUnit methods to set up expected exception instead of annotations 24 | 'general_phpdoc_annotation_remove' => ['annotations' => ['expectedException', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp']], 25 | 'header_comment' => ['header' => $header], 26 | 'heredoc_to_nowdoc' => true, 27 | 'list_syntax' => ['syntax' => 'long'], 28 | 'method_argument_space' => ['ensure_fully_multiline' => true], 29 | 'no_extra_consecutive_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block']], 30 | 'no_null_property_initialization' => true, 31 | 'no_short_echo_tag' => true, 32 | 'no_unreachable_default_argument_value' => true, 33 | 'no_useless_else' => true, 34 | 'no_useless_return' => true, 35 | 'ordered_class_elements' => true, 36 | 'ordered_imports' => true, 37 | 'php_unit_strict' => true, 38 | 'php_unit_test_class_requires_covers' => true, 39 | 'phpdoc_add_missing_param_annotation' => true, 40 | 'phpdoc_order' => true, 41 | 'phpdoc_types_order' => true, 42 | 'semicolon_after_instruction' => true, 43 | 'single_line_comment_style' => true, 44 | 'strict_comparison' => true, 45 | 'strict_param' => true, 46 | ]) 47 | ->setFinder( 48 | PhpCsFixer\Finder::create() 49 | ->exclude('tests/Fixtures') 50 | ->in(__DIR__) 51 | ) 52 | ; 53 | 54 | // special handling of fabbot.io service if it's using too old PHP CS Fixer version 55 | try { 56 | PhpCsFixer\FixerFactory::create() 57 | ->registerBuiltInFixers() 58 | ->registerCustomFixers($config->getCustomFixers()) 59 | ->useRuleSet(new PhpCsFixer\RuleSet($config->getRules())); 60 | } catch (PhpCsFixer\ConfigurationException\InvalidConfigurationException $e) { 61 | $config->setRules([]); 62 | } 63 | 64 | return $config; 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | git: 4 | depth: 1 5 | 6 | cache: 7 | directories: 8 | - $HOME/.composer 9 | 10 | env: 11 | global: 12 | - DEFAULT_COMPOSER_FLAGS="--no-interaction --no-progress" 13 | - COMPOSER_FLAGS="" 14 | 15 | before_install: 16 | # turn off XDebug 17 | - phpenv config-rm xdebug.ini || return 0 18 | 19 | # Composer v2 20 | - composer self-update --2 21 | 22 | jobs: 23 | include: 24 | - 25 | stage: Static Code Analysis 26 | php: 7.4 27 | env: COMPOSER_FLAGS="--no-dev --prefer-stable" 28 | install: 29 | - travis_retry composer update -d dev-tools $DEFAULT_COMPOSER_FLAGS 30 | - composer info -d dev-tools -D | sort 31 | 32 | - travis_retry composer update $DEFAULT_COMPOSER_FLAGS $COMPOSER_FLAGS 33 | - composer info -D | sort 34 | script: 35 | - ./check_trailing_spaces.sh || travis_terminate 1 36 | - ./dev-tools/vendor/bin/phpmd src,tests text phpmd.xml || travis_terminate 1 37 | - ./dev-tools/vendor/bin/composer-require-checker check composer.json || travis_terminate 1 38 | - ./dev-tools/vendor/bin/php-cs-fixer fix -v 39 | dist: xenial 40 | 41 | - &STANDARD_TEST_JOB 42 | stage: Test 43 | php: 5.6 44 | install: 45 | - travis_retry composer update $DEFAULT_COMPOSER_FLAGS $COMPOSER_FLAGS 46 | - composer info -D | sort 47 | script: 48 | - vendor/bin/simple-phpunit 49 | dist: xenial 50 | 51 | - 52 | <<: *STANDARD_TEST_JOB 53 | php: 5.6 54 | env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" 55 | dist: xenial 56 | 57 | - 58 | <<: *STANDARD_TEST_JOB 59 | php: 7.0 60 | 61 | - 62 | <<: *STANDARD_TEST_JOB 63 | php: 7.1 64 | dist: bionic 65 | 66 | - 67 | <<: *STANDARD_TEST_JOB 68 | php: 7.2 69 | dist: bionic 70 | 71 | - 72 | <<: *STANDARD_TEST_JOB 73 | php: 7.3 74 | dist: bionic 75 | 76 | - 77 | <<: *STANDARD_TEST_JOB 78 | php: 7.4 79 | dist: bionic 80 | 81 | - 82 | <<: *STANDARD_TEST_JOB 83 | php: nightly 84 | env: SYMFONY_DEPRECATIONS_HELPER=weak 85 | dist: bionic 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2017 Fabien Potencier 2 | Dariusz Rumiński 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AccessibleObject 2 | 3 | `AccessibleObject` is small class allowing you to easily access internals of any object. 4 | In general, it's bad practice to do so. 5 | While we strongly discourage you to using it, it may be helpful in debugging or testing old, sad, legacy projects. 6 | 7 | # Example 8 | 9 | ```PHP 10 | bar; // PHP Fatal error: Uncaught Error: Cannot access private property Foo::$bar 18 | 19 | $accessibleObject = new AccessibleObject($object); 20 | echo $accessibleObject->bar; // 'baz' 21 | ``` 22 | -------------------------------------------------------------------------------- /check_trailing_spaces.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # copied from https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/v2.4.0/check_trailing_spaces.sh 4 | 5 | files_with_trailing_spaces=$(find . -type f -not -path "./.git/*" -not -path "./dev-tools/vendor/*" -not -path "./vendor/*" -not -path "./tests/Fixtures/*" -exec egrep -nH " $" {} \;) 6 | 7 | if [[ $files_with_trailing_spaces ]] 8 | then 9 | echo -e "\e[97;41mTrailing spaces detected:\e[0m" 10 | e=$(printf '\033') 11 | echo "${files_with_trailing_spaces}" | sed -E "s/^\.\/([^:]+):([0-9]+):(.*[^ ])( +)$/${e}[0;31m - in ${e}[0;33m\1${e}[0;31m at line ${e}[0;33m\2\n ${e}[0;31m>${e}[0m \3${e}[41m\4${e}[0m/" 12 | 13 | exit 1 14 | fi 15 | 16 | echo -e "\e[0;32mNo trailing spaces detected.\e[0m" 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-cs-fixer/accessible-object", 3 | "type": "application", 4 | "description": "A library to reveal object internals.", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Fabien Potencier", 9 | "email": "fabien@symfony.com" 10 | }, 11 | { 12 | "name": "Dariusz Rumiński", 13 | "email": "dariusz.ruminski@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^5.6 || ^7.0 || ^8.0" 18 | }, 19 | "require-dev": { 20 | "symfony/phpunit-bridge": "^5.1" 21 | }, 22 | "config": { 23 | "optimize-autoloader": true, 24 | "sort-packages": true 25 | }, 26 | "autoload": { 27 | "psr-4": { "PhpCsFixer\\AccessibleObject\\": "src/" } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { "PhpCsFixer\\AccessibleObject\\Tests\\": "tests/" } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dev-tools/.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /dev-tools/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php": "^7.4" 4 | }, 5 | "require-dev": { 6 | "friendsofphp/php-cs-fixer": "^2.16.4", 7 | "maglnet/composer-require-checker": "^2.1.1@dev", 8 | "mi-schi/phpmd-extension": "^4.3", 9 | "phpmd/phpmd": "^2.6" 10 | }, 11 | "config": { 12 | "optimize-autoloader": true, 13 | "sort-packages": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phpmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | ./tests 20 | 21 | 22 | 23 | 24 | 25 | ./src 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/AccessibleObject.php: -------------------------------------------------------------------------------- 1 | 7 | * Dariusz Rumiński 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace PhpCsFixer\AccessibleObject; 14 | 15 | /** 16 | * @author Dariusz Rumiński 17 | */ 18 | final class AccessibleObject 19 | { 20 | private $object; 21 | private $reflection; 22 | 23 | /** 24 | * @param object $object 25 | */ 26 | public function __construct($object) 27 | { 28 | $this->object = $object; 29 | $this->reflection = new \ReflectionClass($object); 30 | } 31 | 32 | public function __call($name, array $arguments) 33 | { 34 | if (!method_exists($this->object, $name)) { 35 | throw new \LogicException(sprintf('Cannot call non existing method %s->%s.', \get_class($this->object), $name)); 36 | } 37 | 38 | $method = $this->reflection->getMethod($name); 39 | $method->setAccessible(true); 40 | 41 | return $method->invokeArgs($this->object, $arguments); 42 | } 43 | 44 | public function __isset($name) 45 | { 46 | try { 47 | $value = $this->$name; 48 | } catch (\LogicException $e) { 49 | return false; 50 | } 51 | 52 | return isset($value); 53 | } 54 | 55 | public function __get($name) 56 | { 57 | if (!property_exists($this->object, $name)) { 58 | throw new \LogicException(sprintf('Cannot get non existing property %s->%s.', \get_class($this->object), $name)); 59 | } 60 | 61 | $property = $this->reflection->getProperty($name); 62 | $property->setAccessible(true); 63 | 64 | return $property->getValue($this->object); 65 | } 66 | 67 | public function __set($name, $value) 68 | { 69 | if (!property_exists($this->object, $name)) { 70 | throw new \LogicException(sprintf('Cannot set non existing property %s->%s = %s.', \get_class($this->object), $name, var_export($value, true))); 71 | } 72 | 73 | $property = $this->reflection->getProperty($name); 74 | $property->setAccessible(true); 75 | 76 | $property->setValue($this->object, $value); 77 | } 78 | 79 | public static function create($object) 80 | { 81 | return new self($object); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tests/AccessibleObjectTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Dariusz Rumiński 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace PhpCsFixer\AccessibleObject\Tests; 14 | 15 | use PhpCsFixer\AccessibleObject\AccessibleObject; 16 | use PhpCsFixer\AccessibleObject\Tests\Fixtures\AccessibleObjectTest\DummyClass; 17 | use PHPUnit\Framework\TestCase; 18 | 19 | /** 20 | * @author Dariusz Rumiński 21 | * 22 | * @internal 23 | * 24 | * @covers \PhpCsFixer\Test\AccessibleObject 25 | */ 26 | final class AccessibleObjectTest extends TestCase 27 | { 28 | protected $accessibleObject; 29 | 30 | /** 31 | * @before 32 | */ 33 | public function setUpProperty() 34 | { 35 | $this->accessibleObject = new AccessibleObject(new DummyClass()); 36 | } 37 | 38 | public function testCreate() 39 | { 40 | $object = AccessibleObject::create(new \stdClass()); 41 | 42 | $this->assertInstanceOf('PhpCsFixer\AccessibleObject\AccessibleObject', $object); 43 | } 44 | 45 | public function testGet() 46 | { 47 | $this->assertSame('publicVar_value', $this->accessibleObject->publicVar); 48 | $this->assertSame('privateVar_value', $this->accessibleObject->privateVar); 49 | } 50 | 51 | public function testSet() 52 | { 53 | $this->accessibleObject->publicVar = 'newValue1'; 54 | $this->accessibleObject->privateVar = 'newValue2'; 55 | 56 | $this->assertSame('newValue1', $this->accessibleObject->publicVar); 57 | $this->assertSame('newValue2', $this->accessibleObject->privateVar); 58 | } 59 | 60 | public function testIsset() 61 | { 62 | $this->assertTrue(isset($this->accessibleObject->publicVar)); 63 | $this->assertTrue(isset($this->accessibleObject->privateVar)); 64 | $this->assertFalse(isset($this->accessibleObject->nonExistingVar)); 65 | } 66 | 67 | public function testCall() 68 | { 69 | $this->assertSame('publicMethod_result', $this->accessibleObject->publicMethod()); 70 | $this->assertSame('privateMethod_result', $this->accessibleObject->privateMethod()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Fixtures/AccessibleObjectTest/DummyClass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PhpCsFixer\AccessibleObject\Tests\Fixtures\AccessibleObjectTest; 13 | 14 | /** 15 | * @author Dariusz Rumiński 16 | * 17 | * @internal 18 | */ 19 | final class DummyClass 20 | { 21 | private $privateVar = 'privateVar_value'; 22 | public $publicVar = 'publicVar_value'; 23 | 24 | public function publicMethod() 25 | { 26 | return 'publicMethod_result'; 27 | } 28 | 29 | private function privateMethod() 30 | { 31 | return 'privateMethod_result'; 32 | } 33 | } 34 | --------------------------------------------------------------------------------