Skip to content

Commit 8859d3b

Browse files
authored
Merge pull request #32 from afilina/dont-__toString
add Dont/ToString
2 parents f9ae8f9 + 2b020fd commit 8859d3b

File tree

9 files changed

+186
-2
lines changed

9 files changed

+186
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The package currently provides the following traits:
2525
* [`Dont\DontSet`](docs/DontSet.md)
2626
* [`Dont\DontCall`](docs/DontCall.md)
2727
* [`Dont\DontCallStatic`](docs/DontCallStatic.md)
28+
* [`Dont\DontToString`](docs/DontToString.md)
2829
* [`Dont\JustDont`](docs/JustDont.md)
2930

3031
Usage is straightforward:

docs/DontToString.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# DontToString
2+
3+
Prevent converting an object as a string.
4+
5+
```php
6+
use Dont\DontToString;
7+
8+
class MyClass
9+
{
10+
use DontToString;
11+
}
12+
(new MyClass)->__toString(); // will throw NonStringableObject exception
13+
```

src/Dont/DontToString.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dont;
6+
7+
use Dont\Exception\NonCloneableObject;
8+
use Dont\Exception\NonStringableObject;
9+
use Dont\Exception\TypeError;
10+
11+
trait DontToString
12+
{
13+
/**
14+
* @throws NonStringableObject
15+
* @throws TypeError
16+
*/
17+
final public function __toString() : string
18+
{
19+
throw NonStringableObject::fromAttemptedToString($this);
20+
}
21+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Dont\Exception;
6+
7+
use LogicException;
8+
9+
class NonStringableObject extends LogicException implements ExceptionInterface
10+
{
11+
private const ERROR_TEMPLATE = <<<'ERROR'
12+
The given object %s#%s is not designed to be stringable.
13+
14+
You tried to access a method called "__toString()".
15+
ERROR;
16+
17+
/**
18+
* @return NonStringableObject
19+
*/
20+
public static function fromAttemptedToString(object $object) : self
21+
{
22+
$className = get_class($object);
23+
24+
return new self(sprintf(
25+
self::ERROR_TEMPLATE,
26+
$className,
27+
spl_object_hash($object)
28+
));
29+
}
30+
}

src/Dont/JustDont.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ trait JustDont
1313
use DontClone;
1414
use DontSerialise;
1515
use DontDeserialise;
16+
use DontToString;
1617
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DontTest;
6+
7+
use Dont\DontToString;
8+
use Dont\Exception\NonStringableObject;
9+
use DontTestAsset\DontDoIt;
10+
use DontTestAsset\NonStringable;
11+
use PHPUnit\Framework\TestCase;
12+
13+
/**
14+
* @covers \Dont\DontToString
15+
*/
16+
final class DontToStringTest extends TestCase
17+
{
18+
/**
19+
* @dataProvider nonStringableObject
20+
*
21+
* @param object $object
22+
*/
23+
public function testWillThrowOnToStringMethodAttempt($object) : void
24+
{
25+
$this->expectException(NonStringableObject::class);
26+
27+
$object->__toString();
28+
}
29+
30+
/**
31+
* @dataProvider nonStringableObject
32+
*
33+
* @param object $object
34+
*/
35+
public function testWillThrowOnStringCastAttempt($object) : void
36+
{
37+
$this->expectException(NonStringableObject::class);
38+
39+
(string) $object;
40+
}
41+
42+
/**
43+
* @return object[]
44+
*/
45+
public function nonStringableObject() : array
46+
{
47+
return [
48+
[new NonStringable()],
49+
[new DontDoIt()],
50+
];
51+
}
52+
53+
public function testToStringPreventionIsFinal() : void
54+
{
55+
self::assertTrue((new \ReflectionMethod(DontToString::class, '__toString'))->isFinal());
56+
}
57+
}

tests/DontTest/Exception/NonCallableObjectTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,4 @@ public function nonObjectProvider() : array
7575
[STDERR],
7676
];
7777
}
78-
79-
}
78+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DontTest\Exception;
6+
7+
use Dont\Exception\ExceptionInterface;
8+
use Dont\Exception\NonCloneableObject;
9+
use Dont\Exception\NonStringableObject;
10+
use Dont\Exception\TypeError;
11+
use LogicException;
12+
use PHPUnit\Framework\TestCase;
13+
use stdClass;
14+
15+
/**
16+
* @covers \Dont\Exception\NonStringableObject
17+
*/
18+
final class NonStringableObjectTest extends TestCase
19+
{
20+
/**
21+
* @dataProvider objectProvider
22+
*
23+
* @param object $object
24+
*/
25+
public function testFromAttemptedCloning($object) : void
26+
{
27+
$exception = NonStringableObject::fromAttemptedToString($object);
28+
29+
self::assertInstanceOf(NonStringableObject::class, $exception);
30+
self::assertInstanceOf(LogicException::class, $exception);
31+
self::assertInstanceOf(ExceptionInterface::class, $exception);
32+
33+
$expected = 'The given object ' . get_class($object)
34+
. '#' . spl_object_hash($object) . " is not designed to be stringable.\n\n"
35+
. "You tried to access a method called \"__toString()\".";
36+
37+
self::assertSame($expected, $exception->getMessage());
38+
}
39+
40+
/**
41+
* @return object[][]
42+
*/
43+
public function objectProvider() : array
44+
{
45+
return [
46+
[new stdClass()],
47+
[$this],
48+
];
49+
}
50+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DontTestAsset;
6+
7+
use Dont\DontToString;
8+
9+
final class NonStringable
10+
{
11+
use DontToString;
12+
}

0 commit comments

Comments
 (0)