Skip to content

Commit

Permalink
implemented cache
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Sep 13, 2022
1 parent 8151a24 commit 4fa5cfb
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ DG\BypassFinals::setWhitelist([

This gives you finer control and can solve issues with certain frameworks and libraries.

You can try to increase performance by using the cache (the directory must exist):

```php
DG\BypassFinals::setCacheDirectory(__DIR__ . '/cache');
```

Support Project
---------------
Expand Down
37 changes: 35 additions & 2 deletions src/BypassFinals.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class BypassFinals
/** @var ?object */
private static $underlyingWrapperClass;

/** @var ?string */
private static $cacheDir;


public static function enable(): void
{
Expand All @@ -47,6 +50,12 @@ public static function setWhitelist(array $whitelist): void
}


public static function setCacheDirectory(?string $dir): void
{
self::$cacheDir = $dir;
}


public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool
{
$this->wrapper = $this->createUnderlyingWrapper();
Expand All @@ -60,7 +69,7 @@ public function stream_open(string $path, string $mode, int $options, ?string &$
$content .= $this->wrapper->stream_read(8192);
}

$modified = self::removeFinals($content);
$modified = self::cachedRemoveFinals($content);
if ($modified === $content) {
$this->wrapper->stream_seek(0);
} else {
Expand All @@ -83,12 +92,36 @@ public function dir_opendir(string $path, int $options): bool
}


public static function removeFinals(string $code): string
public static function cachedRemoveFinals(string $code): string
{
if (stripos($code, 'final') === false) {
return $code;
}

if (self::$cacheDir) {
$wrapper = new NativeWrapper;
$hash = sha1($code);
if (@$wrapper->stream_open(self::$cacheDir . '/' . $hash, 'r')) { // @ may not exist
flock($wrapper->handle, LOCK_SH);
if ($res = stream_get_contents($wrapper->handle)) {
return $res;
}
}
}

$code = self::removeFinals($code);

if (self::$cacheDir && @$wrapper->stream_open(self::$cacheDir . '/' . $hash, 'x')) { // @ may exist
flock($wrapper->handle, LOCK_EX);
fwrite($wrapper->handle, $code);
}

return $code;
}


public static function removeFinals(string $code): string
{
try {
$tokens = token_get_all($code, TOKEN_PARSE);
} catch (\ParseError $e) {
Expand Down
2 changes: 1 addition & 1 deletion src/NativeWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public function stream_metadata(string $path, int $option, $value): bool
}


public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool
public function stream_open(string $path, string $mode, int $options = 0, ?string &$openedPath = null): bool
{
$usePath = (bool) ($options & STREAM_USE_PATH);
$this->handle = $this->context
Expand Down
23 changes: 23 additions & 0 deletions tests/BypassFinals/BypassFinals.cache.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

use Tester\Assert;

require __DIR__ . '/../../vendor/autoload.php';

Tester\Environment::setup();


@mkdir($dir = __DIR__ . '/cache');
DG\BypassFinals::setCacheDirectory($dir);

DG\BypassFinals::enable();

require __DIR__ . '/fixtures/final.class.php';

$rc = new ReflectionClass('FinalClass');
Assert::false($rc->isFinal());
Assert::false($rc->getMethod('finalMethod')->isFinal());
Assert::same(123, FinalClass::FINAL);
Assert::same(456, (new FinalClass)->final());

0 comments on commit 4fa5cfb

Please sign in to comment.