Skip to content

PHP Extension for cross-platform filesystem notifications

License

Notifications You must be signed in to change notification settings

genkgo/php-ext-fs-notify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP Extension for cross-platform filesystem notifications

Uses PHPER framework and notify-rs to build the extension. Supports PHP 8.1, 8.2 and 8.3 for Linux and macOS.

Build from source

# For Debian/Ubuntu, llvm version might differ (13/14/15/etc)
sudo apt install gcc make llvm-13-dev libclang-13-dev

# For Alpine Linux, llvm version might differ (13/14/15/etc)
apk add gcc make musl-dev llvm15-dev clang15-dev

# For MacOS
brew install llvm@13
export LIBCLANG_PATH=$(brew --prefix llvm@13)/lib

# recommended rust setup, see https://www.rust-lang.org/tools/install
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# build using cargo
cargo build --release

# move .so (Linux) or .so (MacOS) file to your extension dir
PHP_EXTENSION_DIR=`php -r "echo ini_get('extension_dir');"`
mv target/release/libphp_ext_fs_notify.so ${PHP_EXTENSION_DIR}/fs_notify.so
mv target/release/libphp_ext_fs_notify.dylib ${PHP_EXTENSION_DIR}/fs_notify.dylib

# enable the extension but putting in the ini file
echo 'extension=fs_notify.so' | tee -a /etc/php/${PHP_VERSION}/cli/conf.d/20-fs_notify.ini > /dev/null

Install pre-created .so and .dylib

From the release section download the .so (Ubuntu) or .dylib (macOS) file for your PHP version. Lookup the value of your exension_dir, move the extension into that directory. Enable the extension by putting an ini-file in the conf.d folder of your php version. It might look as follows.

PHP_VERSION=`php -r "echo PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;"`
PHP_EXTENSION_DIR=`php -r "echo ini_get('extension_dir');"`

# download the extension file into the extension dir 
curl -L -o "${PHP_EXTENSION_DIR}/fs_notify.so" "https://github.com/genkgo/php-ext-fs-notify/releases/latest/download/linux-php${PHP_VERSION}-fs_notify.so"

# enable the extension
echo 'extension=fs_notify.so' | tee -a /etc/php/${PHP_VERSION}/cli/conf.d/20-fs_notify.ini > /dev/null

Usage

Create watcher, add paths to watch and start watching with a callback.

$watcher = new FsNotify\RecommendedWatcher();
$watcher->add(__DIR__);
$watcher->add(__DIR__, recursive: false);
$watcher->watch(
    function (FsNotify\Event $event) {
        var_dump($event->getKind()); // kind of file/folder event
        var_dump($event->getPaths()); // paths 
        return true; // return false if you do not want to continue
    }
);

Classes

namespace FsNotify;

class RecommendedWatcher
{
    public function __construct();
    
    public function add(string $path, bool $recursive = true): void;
    
    public function remove(string $path): void;
    
    /**
     * @param callable(Event): bool $handle
     * @throws WatchException
     */
    public function watch(callable $handle): void;
}

class Event
{
    private function __construct();
    
    public function getKind(): string;
    
    /**
     * @return array<int, string>
     */
    public function getPaths(): array;
}

class WatchException extends \Exception
{
}

Why?

Why this extension? With the introduction of native attributes in PHP 8.0, attributes can be placed in many locations. These attributes might influence which actions are available within your application. So the application needs to know these attributes before starting the application. Hence, classes need to be scanned for these attributes.

In our case, the list of folders to scan to see if attribute caches needed to be invalidated, became so large that our development experience suffered from it. Rather than scanning directories on each request, we decided to invalidate caches by watching the folders, and invalidate files that actually changed manually.

Compile

Make sure you have Rust installed. See the PHPER introduction for the required build dependencies.

# for debug purposes
cargo build
# for production
cargo build --release
# run tests
cargo test