Temping
Work with temporary files and folders easily across OSes.
, (*1)
Motivation
Working with temporary files in your tests can be a pain. All good
tests should clean up after themselves, but trying to do this when
working with temporary files can be difficult and error-prone., (*2)
<?php
class MyFilesUsingTestCase extends \PHPUnit_Framework_TestCase {
const file = '/tmp/test-dir/file.txt';
const file2 = '/tmp/test-dir/file2.txt';
public function setUp() {
//create a directory to put temporary files in
mkdir('/tmp/test-dir', 0775, true);
//create the files used in the test
file_put_contents(self::file, 'Hello, world!');
file_put_contents(self::file2, 'Hello, again!);
}
public function tearDown() {
//remove all the created files
unlink(self::file);
unlink(self::file2);
//delete the directory
rmdir('/tmp/test-dir');
//PHP Warning: rmdir(/tmp/test-dir): Directory not empty
//DOH!
}
public function testSomething() {
touch('tmp/test-dir/another-file');
//test some things
}
}
This approach makes it very difficult to efficiently clean up all
temporary files after a test, and doesn't scale well as the test case
grows. And what if the system you're testing on doesn't have /tmp?, (*3)
Temping abstracts away all this pain to make working with temporary
files easy., (*4)
Installation
Temping is installed via Composer. To add it to your project, simply add it to your
composer.json file:, (*5)
{
"require": {
"glynnforrest/temping": "0.5.*"
}
}
And run composer to update your dependencies:, (*6)
$ curl -s http://getcomposer.org/installer | php
$ php composer.phar update
Usage
Get a Temping instance, (*7)
$temp = new Temping\Temping();
//or in a custom directory of your choice
$temp = new Temping\Temping('path/to/my/dir');
Creating a blank file, (*8)
$temp->create('my-file.txt');
//automatically create subdirectories too
$temp->create('file/in/sub/directory.php')
Creating an empty directory, (*9)
$temp->createDirectory('storage');
//automatically create subdirectories too
$temp->createDirectory('storage/with/sub/directories')
Creating a file with contents, (*10)
$temp->create('my/file.txt', 'Hello, world!');
Work with the contents of the file after creation using setContents()
and getContents()., (*11)
$filename = 'file.txt';
$temp->create($filename);
$temp->setContents($filename, 'Hello, world!');
echo $temp->getContents($filename);
//Hello, world!
Files that are created, modified or deleted outside of the Temping
class are still accessible., (*12)
file_put_contents($temp->getDirectory() . 'foo.txt', 'Hello, world!');
echo $temp->getContents('foo.txt');
//Hello, world!
Get the full path name of a file, (*13)
$filename = 'my-file.php';
$temp->create($filename);
echo $temp->getPathname($filename);
// /tmp/php-temping/my-file.php
Get the full path to the Temping directory, (*14)
echo $temp->getDirectory();
// /tmp/php-temping/
To do other fancy things with your temporary files, you can grab a
SplFileObject instance., (*15)
$filename = 'my-file.php';
$temp->create($filename);
$obj = $temp->getFileObject($filename);
echo $obj->getExtension();
//php
The default mode of the SplFileObject is read-only, 'r'. Pass any
accepted parameter to fopen() as the second argument to get a
different mode., (*16)
$filename = 'my-file.txt';
$temp->create($filename);
$obj = $temp->getFileObject($filename, 'w');
//Now able to write to my-file.txt
Delete a file or directory, (*17)
$temp->delete('my-file.txt');
$temp->delete('my-directory/');
If a directory is not empty, the deletion will fail. Pass true as a
second argument to delete a non-empty directory too., (*18)
$temp->delete('non-empty-directory/', true);
To check if a file or directory has been created, use exists()., (*19)
$this->temp->createDirectory('some/dir');
$this->temp->exists('some/dir');
//true
$this->temp->create('foo/bar.txt');
$this->temp->exists('foo/bar.txt');
//true
$this->temp->exists('something');
//false
Leave the $path argument blank to check if the temping directory
exists., (*20)
$this->temp->exists();
//true
$this->temp->reset();
$this->temp->exists();
//false
Exists will also check for files that weren't created by Temping
explicitly, but are still present in the temporary directory. This is
useful for testing code that is expected to create files., (*21)
touch($temp->getDirectory() . 'foo.txt');
$temp->exists('foo.txt');
//true
//In a test. Assume MyLogger takes the log directory in the
//constructor
$obj = new MyLogger($temp->getDirectory());
$obj->log('testing');
$this->assertTrue($temp->exists('log.log'));
To check if a directory is empty, use isEmpty(). This function will
also return true if the directory doesn't exist., (*22)
$this->temp->createDirectory('foo/bar');
$this->temp->isEmpty('foo/bar');
//true
$this->temp->create('foo/bar/baz.txt');
$this->temp->isEmpty('foo/bar');
//false
Leave the $dir argument blank to check if the temping directory is
empty., (*23)
$this->temp->isEmpty();
//true
$this->temp->create('foo.php');
$this->temp->isEmpty();
//false
To obliterate all the files in the temporary directory, plus the
directory itself, call reset()., (*24)
$temp->create('file1.txt')->create('file2.txt')->create('file3.txt');
$temp->reset();
All files inside the temporary directory will be deleted, including
those that weren't created by Temping explicitly., (*25)
If you need to recreate the temporary directory after calling reset(),
use init(). By default, init() is called by all Temping methods that
modify the filesystem., (*26)
$temp->reset();
//temporary directory doesn't exist any more
$temp->create('foo');
//temporary directory recreated automatically
$obj = new MyLogger($temp->getDirectory());
$temp->reset();
//temporary directory doesn't exist any more
$temp->init();
//temporary directory recreated for MyLogger to use
Also, if you want to use the temporary directory as the location to
test something, but not actually call any Temping methods, call init()
to create the directory manually., (*27)
$obj = new MyLogger($temp->getDirectory());
//no methods called on $temp yet, so temporary directory doesn't exist
$temp->init();
//temporary directory recreated for MyLogger to use
Now armed with Temping, MyFilesUsingTestCase can be refactored., (*28)
<?php
class MyFilesUsingTestCase extends \PHPUnit_Framework_TestCase {
protected $temp;
public function setUp() {
$this->temp = new Temping\Temping();
$this->temp->create('file.txt', 'Hello, world!')
->create('file2.txt', 'Hello, again!);
}
public function tearDown() {
$this->temp->reset();
}
public function testSomething() {
$this->temp->create('another-file');
}
}
Much better!, (*29)
Chainable methods
Methods return the Temping instance where it makes sense. This makes
it easy to do stuff like this:, (*30)
$temp->create('foo')
->create('bar', 'Hello world')
->setContents('foo', 'bar')
->delete('bar')
->reset();
The methods init(), reset(), create(),
createDirectory(), delete() and setContents() are chainable., (*31)
Where are the files stored?
If you don't specify a directory in the constructor, Temping uses the
output of sys_get_temp_dir() to decide where to store the temporary
files., (*32)
For example:, (*33)
'file.txt' => '/tmp/php-temping/file.txt', (*34)
'dir/subdir/file.txt' => '/tmp/php-temping/dir/subdir/file.txt', (*35)