-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
83f95fa
commit 5676ac4
Showing
8 changed files
with
484 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Kdyby (http://www.kdyby.org) | ||
* | ||
* Copyright (c) 2008 Filip Procházka ([email protected]) | ||
* | ||
* For the full copyright and license information, please view the file license.txt that was distributed with this source code. | ||
*/ | ||
|
||
namespace Kdyby\StrictObjects; | ||
|
||
use Kdyby; | ||
use Nette; | ||
|
||
|
||
|
||
/** | ||
* @author Filip Procházka <[email protected]> | ||
* @author David Grudl <https://davidgrudl.com> | ||
*/ | ||
trait Scream | ||
{ | ||
|
||
/** | ||
* Call to undefined method. | ||
* | ||
* @param string $name method name | ||
* @param array $args arguments | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
*/ | ||
public function __call($name, $args) | ||
{ | ||
$class = get_class($this); | ||
$hint = Suggester::suggestMethod($class, $name); | ||
throw new MemberAccessException("Call to undefined method $class::$name()" . ($hint ? ", did you mean $hint()?" : '.')); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Call to undefined static method. | ||
* | ||
* @param string $name method name (in lower case!) | ||
* @param array $args arguments | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
*/ | ||
public static function __callStatic($name, $args) | ||
{ | ||
$class = get_called_class(); | ||
$hint = Suggester::suggestStaticFunction($class, $name); | ||
throw new MemberAccessException("Call to undefined static method $class::$name()" . ($hint ? ", did you mean $hint()?" : '.')); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Returns property value. Do not call directly. | ||
* | ||
* @param string $name property name | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
*/ | ||
public function &__get($name) | ||
{ | ||
$class = get_class($this); | ||
$hint = Suggester::suggestProperty($class, $name); | ||
throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Sets value of a property. Do not call directly. | ||
* | ||
* @param string $name property name | ||
* @param mixed $value property value | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
* @return void | ||
*/ | ||
public function __set($name, $value) | ||
{ | ||
$class = get_class($this); | ||
$hint = Suggester::suggestProperty($class, $name); | ||
throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Is property defined? | ||
* | ||
* @param string $name property name | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
* @return bool | ||
*/ | ||
public function __isset($name) | ||
{ | ||
$class = get_class($this); | ||
$hint = Suggester::suggestProperty($class, $name); | ||
throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Access to undeclared property. | ||
* | ||
* @param string $name property name | ||
* @throws \Kdyby\StrictObjects\MemberAccessException | ||
* @return void | ||
*/ | ||
public function __unset($name) | ||
{ | ||
$class = get_class($this); | ||
throw new MemberAccessException("Cannot unset the property $class::\$$name."); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Kdyby (http://www.kdyby.org) | ||
* | ||
* Copyright (c) 2008 Filip Procházka ([email protected]) | ||
* | ||
* For the full copyright and license information, please view the file license.txt that was distributed with this source code. | ||
*/ | ||
|
||
namespace Kdyby\StrictObjects; | ||
|
||
use Kdyby; | ||
use Nette; | ||
|
||
|
||
|
||
/** | ||
* @author Filip Procházka <[email protected]> | ||
*/ | ||
final class Suggester | ||
{ | ||
|
||
/** | ||
* @param string $class | ||
* @param string $method | ||
* @return NULL|string | ||
*/ | ||
public static function suggestMethod($class, $method) | ||
{ | ||
return self::getSuggestion( | ||
get_class_methods($class), | ||
$method | ||
); | ||
} | ||
|
||
|
||
|
||
/** | ||
* @param string $class | ||
* @param string $method | ||
* @return NULL|string | ||
*/ | ||
public static function suggestStaticFunction($class, $method) | ||
{ | ||
return self::getSuggestion( | ||
array_filter( | ||
get_class_methods($class), | ||
function ($m) use ($class) { | ||
return (new \ReflectionMethod($class, $m))->isStatic(); | ||
} | ||
), | ||
$method | ||
); | ||
} | ||
|
||
|
||
|
||
/** | ||
* @param string $class | ||
* @param string $name | ||
* @return NULL|string | ||
*/ | ||
public static function suggestProperty($class, $name) | ||
{ | ||
return self::getSuggestion( | ||
array_keys(get_class_vars($class)), | ||
$name | ||
); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Finds the best suggestion (for 8-bit encoding). | ||
* | ||
* @author David Grudl (https://davidgrudl.com) | ||
* @license See https://nette.org/en/license | ||
* @return string|NULL | ||
* @internal | ||
*/ | ||
public static function getSuggestion(array $items, $value) | ||
{ | ||
$norm = preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '', $value); | ||
$best = NULL; | ||
$min = (strlen($value) / 4 + 1) * 10 + .1; | ||
foreach (array_unique($items) as $item) { | ||
if ($item !== $value && ( | ||
($len = levenshtein($item, $value, 10, 11, 10)) < $min | ||
|| ($len = levenshtein(preg_replace($re, '', $item), $norm, 10, 11, 10) + 20) < $min | ||
) | ||
) { | ||
$min = $len; | ||
$best = $item; | ||
} | ||
} | ||
return $best; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Kdyby (http://www.kdyby.org) | ||
* | ||
* Copyright (c) 2008 Filip Procházka ([email protected]) | ||
* | ||
* For the full copyright and license information, please view the file license.txt that was distributed with this source code. | ||
*/ | ||
|
||
namespace Kdyby\StrictObjects; | ||
|
||
interface Exception | ||
{ | ||
|
||
} | ||
|
||
|
||
|
||
class MemberAccessException extends \LogicException implements Exception | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
coverage.dat | ||
*.actual | ||
*.expected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<?php | ||
|
||
/** | ||
* @testCase | ||
*/ | ||
|
||
namespace KdybyTests\Doctrine\MagicAccessors; | ||
|
||
use KdybyTests\StrictObjects\SomeObject; | ||
use Tester; | ||
use Tester\Assert; | ||
|
||
require_once __DIR__ . '/bootstrap.php'; | ||
|
||
|
||
|
||
/** | ||
* @author Filip Procházka <[email protected]> | ||
*/ | ||
class ScreamTest extends Tester\TestCase | ||
{ | ||
|
||
public function testMagicCall() | ||
{ | ||
$o = new SomeObject(); | ||
|
||
Assert::exception(function () use ($o) { | ||
$o->someBaZ(); | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Call to undefined method KdybyTests\StrictObjects\SomeObject::someBaZ(), did you mean someBar()?'); | ||
} | ||
|
||
|
||
|
||
public function testMagicStaticCall() | ||
{ | ||
Assert::exception(function () { | ||
SomeObject::staBaz(); | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Call to undefined static method KdybyTests\StrictObjects\SomeObject::staBaz(), did you mean staBar()?'); | ||
} | ||
|
||
|
||
|
||
public function testMagicGet() | ||
{ | ||
$o = new SomeObject(); | ||
|
||
Assert::exception(function () use ($o) { | ||
$o->baz; | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Cannot read an undeclared property KdybyTests\StrictObjects\SomeObject::$baz, did you mean $bar?'); | ||
} | ||
|
||
|
||
|
||
public function testMagicSet() | ||
{ | ||
$o = new SomeObject(); | ||
|
||
Assert::exception(function () use ($o) { | ||
$o->baz = 'value'; | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Cannot write to an undeclared property KdybyTests\StrictObjects\SomeObject::$baz, did you mean $bar?'); | ||
} | ||
|
||
|
||
|
||
public function testMagicUnset() | ||
{ | ||
$o = new SomeObject(); | ||
|
||
Assert::exception(function () use ($o) { | ||
unset($o->baz); | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Cannot unset the property KdybyTests\StrictObjects\SomeObject::$baz.'); | ||
} | ||
|
||
|
||
|
||
public function testMagicIsset() | ||
{ | ||
$o = new SomeObject(); | ||
|
||
Assert::exception(function () use ($o) { | ||
isset($o->baz); | ||
}, 'Kdyby\StrictObjects\MemberAccessException', 'Cannot write to an undeclared property KdybyTests\StrictObjects\SomeObject::$baz, did you mean $bar?'); | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
(new ScreamTest())->run(); |
Oops, something went wrong.