My home-made simple logger (just a wrapper around fopen, fwrite, fclose) should be enabled or disabled on the fly. I think the way i'm checking if logging is enable is overkill (every call to a logging method requires to evaluate LOGGING):
config.inc.php
define('LOGGING', true);
logger.php
public function __construct($filename)
{
$this->fp = fopen($filename, 'w+');
}
public function __destruct()
{
fclose($this->fp);
}
public function warn($message)
{
$this->log('WARN', $message);
}
private function log($type, $message)
{
if(!defined(LOGGING) || !LOGGING) return;
fwrite($this->fp, "[$type] $message\n");
}
Question: how to initialize file handler to something like null and remove the check for LOGGING? I mean something like this:
public function __construct($filename)
{
// Create a fake stream if logging is disabled
$this->fp = !defined(LOGGING) || !LOGGING ? null : fopen($filename, 'w+);
}
Future call to $logger->warn('Ops..') should do nothing, without triggering any error or notice.
I mentioned it as a comment above. However, now once again as an answer, because now I think it is one.
You can create a special logger subclass, something like
class NullLogger implements Logger {
public function log ($message) { /* No operation */ }
}
When LOGGING is false, just use this log class and every call with just doing nothing, what will reduce the overhead to the absolute minimum.
This approach has even an own name/pattern: http://en.wikipedia.org/wiki/Null_Object_pattern
You can extend this class and override the log method (leave empty body for example). Then if logging is disabled, create object of child class.
The overhead of file operations is going to VASTLY outweight the overhead of doing if (LOGGING) { ... }. You're optimizing the entirely wrong thing. Checking if LOGGING is true is a simple single value comparison. By comparison, a file operation, even if you're writing to /dev/null, requires invoking file system operations, OS buffers, permissions checks, blah blah blah.
I don't know about you, but I'll do the operation that costs $0.01 each versus one that has the same effect but costs $100 each time.
Related
I have following question:
I am programming a SOAP Server application with PHP. But I have to do that in two different ways, one which is for external usage (for all people) and one that is just for an import. And the import application has just a little bit more possibilities, but else it is the same.
In C I would write something like this (using the preprocessor):
#ifdef INTERNAL
int funktion( int ok, double asdfg, const char *aaa){
#else
int funktion( int ok, double asdfg){
#endif
return 0;
}
I know the function defined() in PHP, but it does not really do what I want to do (I think).
But is there something simolar?
Of course I could write two different applications, but it would be very great if there was something like this ...
Thank you for help!
EDIT:
I know that normally it is possible to write conditional functions like
if(CST){
function asdf($asdf){
}
}
else{
function asdf(){}
}
but I need it in a Class and there it does not work ...
Kind regards!
In PHP there are no such pre-processing constructs as PHP is not compiled. But in PHP classes can be defined conditionally. So you could do this in two steps:
define the class with the full option (3rd argument), but define those sensitive members as protected instead of public
extend the class conditionally, providing access to the protected members via a new name, and with the appropriate signature. Other public members do not have to be mentioned explicitly as they are inherited as usual
Here is an example:
define('INTERNAL', false);
// Define complete class, but with members set to protected
// when they have constraints depending on INT/EXT access
class _myClass {
protected function _funktion ($ok, $str, $id = -1) {
echo "arguments: $ok,$str,$id";
}
public function otherFunc() {
echo "other func";
}
}
// Define myClass conditionally
if (INTERNAL) {
class myClass extends _myClass{
// give public access to protected inherited method
public function funktion ($ok, $str, $id) {
$this->_funktion ($ok, $str, $id);
}
}
} else {
class myClass extends _myClass{
// give public access to protected inherited method, but only
// with 2 parameters
function funktion ($ok, $str) {
$this->_funktion ($ok, $str);
}
}
}
$obj = new myClass();
// if signature has 2 arguments, third is ignored
$obj->funktion(1, 'test', 3);
// other methods are availble
$obj->otherFunc();
I know it's an old question, and a little different, but FWIW I was looking for some more elegant way, than the one I use now, to have a debug/release run, i.e. a kind of conditional compilation.
So far I couldn't find anything better than running some code inside the assert (https://www.php.net/manual/en/function.assert.php). Here's one of possible use cases:
function debugMsg(string $message): bool
{
echo $message . PHP_EOL;
return true;
}
.....
assert(debugMsg("some debug message"));
Then I can conditionally set 'zend.assertions' to '0' for release or to '1' for debug (using ini_set).
As a result, having a very heavy processing (performance test) and running the code in the "debug mode", gives me tons of output and allows me to see lots of details for debugging purpose, but it works up to 10 times slower than in the "release mode" with all that logging skipped.
Note:
that code (the function call) should return true to work correctly
the 'zend.assertions' shouldn't be '-1' in the php.ini, because otherwise the code for assert is not even generated for execution, and thus cannot be controlled inside the code.
I'm having problems with accessing resources from global context using php pthreads for Windows.
The logic is very simple: there's a Server as a main class, only one, which will:
create logfile
create couple of threads
each thread will need to write something to this logfile
Problem is, the resource of logfile handle is somehow totally messed up from inside the thread. When I create the resource, it's fine, I can write in it. When I try to call the log from inside the running thread, the resource of logfile handler appears to be integer 0, not even a resource.
Here's my code:
$main_server = new CMainServer();
$main_server->init();
$main_server->go();
$main_server->log("All done");
Inside the CMainServer class:
class CMainServer
{
private $logfile = null;
public function init()
{
$this->logfile = fopen('wstext.log', 'w');
}
public function log($str)
{
if ($this->logfile === null)
{
echo "[".date("H:i:s", time())."]: logfile is null<BR />";
return false;
}
if (!is_resource($this->logfile))
{
echo "[".date("H:i:s", time())."]: logfile is NOT a resource, can't write {$str}<BR />";
return false;
}
echo "[".date("H:i:s", time())."]: logfile is resource, not null, writing {$str}<BR />";
flush();
fwrite($this->logfile, "[".date("H:i:s", time())."]: {$str}\r\n");
return true;
}
public function go()
{
$this->log('Before creating a thread');
$first_thread = new CThread();
$first_thread->start(PTHREADS_INHERIT_ALL | PTHREADS_ALLOW_GLOBALS);
$second_thread = new CThread();
$second_thread->start(PTHREADS_INHERIT_ALL | PTHREADS_ALLOW_GLOBALS);
$first_thread->join();
$second_thread->join();
}
public function __destruct()
{
if ($this->logfile)
fclose($this->logfile);
}
}
And, finally, the CThread class:
class CThread extends Thread
{
public function run()
{
global $main_server;
$thread_id = $this->getThreadId();
Thread::globally(function()
{
for ($i = 0; $i < 2; $i++)
{
$main_server->log("({$i}) writing random number ".rand(0, 100)." to log from running thread id={$thread_id}");
sleep(1);
}
});
}
}
Result is sad:
[13:38:10]: logfile is NOT a resource, can't write (0) writing random number 21 to log from running thread id=9080
[13:38:11]: logfile is NOT a resource, can't write (1) writing random number 91 to log from running thread id=9080
[13:38:10]: logfile is NOT a resource, can't write (0) writing random number 16 to log from running thread id=17316
[13:38:11]: logfile is NOT a resource, can't write (1) writing random number 50 to log from running thread id=17316
[13:38:10]: logfile is resource, not null, writing Before creating a thread
[13:38:12]: logfile is resource, not null, writing All done
So while I'm outside the thread, all is fine. However, from within a thread the $logfile is not a resource at all.
I tried different options: tried calling from CThread::run() a global function:
function LogFromThread($i, $thread_id)
{
global $main_server;
$main_server->log("({$i}) writing random number ".rand(0, 100)." to log from running thread id={$thread_id}");
}
The result is the same.
Tried without Thread::globally() at all, but all for no good.
I'm running Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.6.3, tried pthreads version 2.0.8, 2.0.9. Also tried with PHP 7RC2 and RC3, but there seems to be a problem to start a new thread at all, apache logs an error, so I returned to 5.6.3.
Maybe someone could give me a hint out about this?
Much appreciated! =)
Do not try to use globals in threads.
The PTHREADS_ALLOW_GLOBALS constant and functionality is there for a special use case, it is not intended for use by everyone, in addition globally has been removed in v3.
It is not a good idea to use threads at the frontend of a web application.
You will not be able to load pthreads v3 in Apache any longer
There is a much tidier way of doing what you want to do, that actually works.
Resources are officially unsupported, that doesn't mean you can't use them, it means you shouldn't expect to be able to share them among contexts.
In this case, you don't need to share the resource and so should not try, nor should you try to do anything in the global scope.
Follows is some PHP7 code (which I recommend new projects should use as pthreads v3 is vastly superior to v2):
<?php
class Logger extends Threaded {
public function __construct(string $file) {
$this->file = $file;
}
private function getHandle() {
if (!self::$handle) {
self::$handle = fopen($this->file, "a");
}
return self::$handle;
}
public function log(string $message, ... $args) {
return $this->synchronized(function() use($message, $args) {
return vfprintf($this->getHandle(), $message, $args);
});
}
private $file;
private static $handle;
}
class My extends Thread {
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function run() {
while (#$i++<100) {
$this->logger->log("Hello %s from %s #%lu\n",
"World", __CLASS__, $this->getThreadId());
/* just simulating work, don't need to wait here */
$this->synchronized(function(){
$this->wait(1000);
});
}
}
private $logger;
}
$logger = new Logger("/tmp/log.txt");
$threads = [];
while (#$i++ < 10) {
$threads[$i] = new My($logger);
$threads[$i]->start();
}
foreach ($threads as $thread)
$thread->join();
?>
In the Logger you will notice that the handle is stored statically, which for pthreads means thread-local.
This means that each thread has a handle to the log, which is how resources are intended to be used in PHP.
You will also notice, the log method is wrapped in a synchronized block, the reason is this: If many threads attempt to write a log at the same time, you will have a log filled with gibberish.
Synchronizing provides mutual exclusion, so that only one thread may write the log at a time, I create ten threads and have them all write to the log one hundred times, no gibberish comes out, it will behave like that everywhere.
A little bit about file locking (flock): On some operating systems, in some circumstances, append is atomic. It's worth mentioning because you should never rely on this, nor should you try to force the writes to be atomic with flock, since flock only places advisory locks on a file: A process executing with the correct permissions is free to ignore flocks and manipulate the file anyway.
Scary stuff, don't rely on append being atomic, and don't rely on flock is the only sensible advice in the context of multi-threading.
On a side note, if you think you have found a bug in pthreads (v3, PHP7), please report it on github.
I have this function I want to test looking like this:
class Logger {
function error($msg){
if (is_string($msg)){
error_log($msg);
die($msg);
} elseif (is_object($msg)){
error_log($msg.' '.$msg->getTraceAsString());
die('exception');
} else {
var_dump($msg);
die('error');
}
}
I want to test this function without logging the $msg. Is there a way to determine if error_log works without logging? I tried using setExpectedException but I wasn't able to catch the error and it kept logging.
The obvious answer is a simple alias/proxy-function that itself called error_log in the Logger class (which can be easily mocked, and checked to see what is set to it),
To actually test the native error_log function however (without a proxy in the original class), can be done with namespaces. The test would end up defined to be the same namespace as the original code, and then after the test class, add a function - in this case error_log() - but that function is also defined in the namespace - and so would be run in preference to the root-namespace-equivalent from the native functions.
Unfortunately, you can't do the same overriding with die (or its alias, exit). They are 'language constructs', and cannot be overridden like error_log can.
<?php
namespace abc;
use abc\Logger;
class ThreeTest extends \PHPUnit_Framework_TestCase
{
public function setUp() { $this->l = new Logger(); }
// test code to exercise 'abc\Logger'
}
// Now define a function, still inside the namespace '\abc'.
public function error_log($msg)
{
// this will be called from abc\Logger::error
// instead of the native error_log() function
echo "ERR: $msg, ";
}
you can use a function-mocking framework like php-mock (there are others as well) to mock the call to error_log (and check whether it is called with your expected parameters).
Unfortunately you will not be able to use that for the die-construct as that is not a normal function but anlanguage construct.
I'd replace the die() with a 'throw new \Exception()' (or any other appropriate exception) as you can then
test for the thrown exception and
can decide in your programming whether execution shall be stopped on calling the logger or whether you want to go on by wrapping the call into a try/catch
But I'd also ask myself whether the execution has to stop when calling a logger
Capturing error_log() output in a variable
If you want to redirect the error_log() output in a way that lets you inspect it with PHPUnit assertions, the following code works for me:
$errorLogTmpfile = tmpfile();
$errorLogLocationBackup = ini_set('error_log', stream_get_meta_data($errorLogTmpfile)['uri']);
error_log("Test for this message");
ini_set('error_log', $errorLogLocationBackup);
$result = stream_get_contents($errorLogTmpfile);
// Result: [11-May-2022 22:27:08 UTC] Test for this message
As you can see, it uses a temporary file to collect the output, then grabs the content into a variable and resets the error_log config.
Re-usable methods
Personally, I've organized this into a pair of methods that I inject into the PHPUnit object with a trait so I can re-use them.
Of course the code below won't work out of the box, but it serves to demonstrate how you can make this system re-usable:
trait WithWPTestCaseGeneralTools {
var $gvErrorLogLocationBackup = "";
var $gvErrorLogTmpfile = "";
public function gvErrorLogStartListening() {
$this->gvErrorLogTmpfile = tmpfile();
$streamUri = stream_get_meta_data($this->gvErrorLogTmpfile)['uri'];
$this->gvErrorLogLocationBackup = ini_set('error_log', $streamUri);
}
public function gvErrorLogGetContents() {
ini_set('error_log', $this->gvErrorLogLocationBackup);
return stream_get_contents($this->gvErrorLogTmpfile);
}
}
You could of course achieve the same things with a couple of functions that use globals, I'll leave that to you if it's what you need!
I'm training a PHP script to run as a well behaved cron job. To escape infinite loops and such I've added set_time_limit.
As far as I know there is not finally clause functionality for PHP. I would like to have such functionality to cleanup, like unlinking files when the time limit is reached.
What would be an alternative way to accomplish this?
Bruce Aldridge already answered, how it can be reached.
I show you another way: RAII pattern (not to say that is better or worse)
Example:
class AutoUnlinker
{
private $files;
public function OpenFile($filepath, $mode)
{
$handler = fopen($filepath, $mode);
$this->files[$filepath] = $handler;
return $handler;
}
public function __destruct()
{
if (!empty($this->files))
{
foreach ($this->files as $filepath => $handler)
{
if (!empty($handler)) fclose($handler);
if (file_exists($filepath)) unlink($filepath);
}
}
}
}
If this class will be used for opening files, all files will be closed and unlinked on script termination. This example specially for your question - usually 1 object being used to give access to 1 resource.
http://php.net/manual/en/function.register-shutdown-function.php
actually, this won't run on script timeout.
and it would be better to handle catches for infinite loops in the code.
Please give me some real life examples when you had to use __destruct in your classes.
Ok, since my last answer apparently didn't hit the mark, let me try this again. There are plenty of resources and examples on the internet for this topic. Doing a bit of searching and browsing other framework's code and you'll see some pretty good examples...
Don't forget that just because PHP will close resources on termination for you doesn't mean that it's bad to explictly close them when you no longer need them (or good to not close them)... It depends on the use case (is it being used right up to the end, or is there one call early on and then not needed again for the rest of execution)...
Now, we know that __destruct is called when the object is destroyed. Logically, what happens if the object is destroyed? Well, it means it's no longer available. So if it has resources open, doesn't it make sense to close those resources as it's being destroyed? Sure, in the average web page, the page is going to terminate shortly after, so letting PHP close them usually isn't terrible. However, what happens if for some reason the script is long-running? Then you have a resource leak. So why not just close everything when you no longer need it (or considering the scope of the destructor, when it's no longer available)?
Here's some examples in real world frameworks:
Lithium's lithium\net\Socket class
Kohana's Memcached Driver
Joomla's FTP Implementation
Zend Frameworks's SMTP Mail Transport Class
CodeIgniter's TTemplate Class
A Tidy Filter Helper for Cake
A Google-Groups Thread about using Destructors For the Symfony Session Class
The interesting thing is that Kohana keeps track of the tags, so that it can delete by "namespace" later (instead of just clearing the cache). So it uses the destructor to flush those changes to the hard storage.
The CodeIgniter class also does something interesting in that it adds debugging output to the output stream in the destructor. I'm not saying this is good, but it's an example of yet another use...
I personally use destructors whenever I have long running processes on my master controller. In the constructor, I check for a pid file. If that file exists (And its process is still running), I throw an exception. If not, I create a file with the current processes id. Then, in the destructor I remove that file. So it's more about cleaning up after itself than just freeing resources...
There is another handy use to generate HTML page
class HTMLgenerator {
function __construct() {
echo "<html><body>";
}
function __destruct() {
echo "</body></html>";
}
}
With this class, you can write
$html = new HTMLgenerator();
echo "Hello, world!";
And the result is
<html><body>Hello, world!</body></html>
For example:
<?php
class Session
{
protected $data = array();
public function __construct()
{
// load session data from database or file
}
// get and set functions
public function __destruct()
{
// store session data in database or file
}
};
This is a good why to use destruct. You prevents reading and writing to a session source all the time and do this only at the start and at the end.
I create a php page what will generate a movie information jpg file. This page will have to gather a few information and run inkscape to convert template (an svg file) to a png before converting to jpg. The svg contain relative links to other image which must be a file. So my page download necessary files into a temporary folder, convert the svg file. At the end, the temporary folder must be deleted.
I put the temporary folder deletion into the destructor. Before there can be many reason the page ends unexpected and the only think I can be sure is that destructor will be call when page exit.
Hope this helps.
A destructor is extremely useful if you use a custom database connector/wrapper.
In the constructor, you can pass the connection information. Because you can use a destructor (rather than a finalizer, etc.,) you can rely on that to close the connection for you. It's more of a convenience, but it certainly is useful.
For example, when PHP decides to explicitly "free" the object (i.e., it is no longer used,) it will call the destructor at that time. This is more useful in the scenario I describe as you're not waiting for the garbage collector to run and call the finalizer.
$0.02
Ian
<?php
class Database
{
private $connection;
private $cache = array();
function __construct([$params])
{
//Connection here
}
//Query
public function query(Query $Query)
{
if($this->is_cached($Query->checksum))
{
return $this->get_cache($Query->checksum);
}
//...
}
public function __destruct()
{
unset($this->connection);
$this->WriteCache();
unset($this->cache);
shutdown_log($this,'Destruction Completed');
}
}
?>
theres an example that should make you understand.
If you use handles returned by fopen() for say, logging, you can use __destruct() to make sure fclose() is called on our resources when your class is destroyed.
You are right, __destruct is mostly unnecessary for the short running php scripts. Database connections, file handles and so on close on script exit or sometimes even earlier if variables run out of scope.
One example i can think of is writing logs to the database. Since we didn't want to fire one query per log entry that gets created somewhere in the script we wrote the "write to db" part in the __destruct of the logging class so when the script ends everything gets inserted into the database at one.
Another example: If you allow a user to upload files the destructor is sometimes a nice places to delete the temp file (in case something goes wrong in the script it at least get cleaned up)
But even for filehandles it can be useful. I've worked on a application that did use the old fopen etc. calls wrapped in objects and when using those on large filetrees php would run out of filehandles sooner or later, so cleaning up while the script was running was not only nice but necessary.
I use APC caching for large numbers of "low level" objects, that otherwise would use excessive memory; and I have a cacheCollection object that handles the reading and writing of those "low level" objects to and from APC during execution of the script. When the script terminates, the objects must be cleared down from APC, so I use the cacheCollection __destruct method to perform that function.
I have used __destruct() in a logging class that wrapped a database connection:
<?php
class anyWrap
{
private $obj,$calls,$log,$hooks;
function anyWrap($obj, $logfile = NULL)
{
if(is_null($logfile))
{
$this->log = dirname(__FILE__) . "/../logs/wrapLog.txt";
}
$this->hooks = array();
$this->dbCalls = 0;
$this->obj = $obj;
}
public function __set($attri, $val) {
$this->obj->$attri = $val;
}
public function __get($attri) {
return $this->obj->$attri;
}
public function __hook($method)
{
$this->hooks[] = $method;
}
public function __call($name,$args)
{
$this->calls++;
if(in_array($name,$this->hooks))
{
file_put_contents($this->log,var_export($args,TRUE)."\r\n",FILE_APPEND);
}
return call_user_func_array(array($this->obj,$name),$args);
}
//On destruction log diagnostics
public function __destruct()
{
unset($this->dbReal);
file_put_contents($this->log,$this->calls."\r\n",FILE_APPEND);
}
}
The script hooks into the database calls and logs the prepare statements, then when the script has run to an end (I don't always know when) it will finally log the number of calls to the database to the file. This way I can see how many times certain functions has been called on the database and plan my optimization accordingly.
If you are creating a view using a PHP script in a MySQL database, you must drop that view at the end of the script. Because if not, the next time that script is executed view will not be created, as there is already a view of similar name in the database. For this purpose you can use destructor.
Here's a rather unusual use case for destructors that I think libraries such as pest are using to combine method chaining with functions or in other words, to achieve fluent interface for functions, Which goes like this:
<?php
class TestCase {
private $message;
private $closure;
private $endingMessage;
public function __construct($message, $closure) {
$this->message = $message;
$this->closure = $closure;
}
public function addEndingMessage($message) {
$this->endingMessage = $message;
return $this;
}
private function getClosure() {
return $this->closure;
}
public function __destruct() {
echo $this->message . ' - ';
$this->getClosure()();
echo $this->endingMessage ? ' - ' . $this->endingMessage : '';
echo "\r\n";
}
}
function it($message, $closure) {
return new TestCase($message, $closure);
}
it('ok nice', function() {
echo 'what to do next?';
});//outputs: ok nice - what to do next?
it('ok fine', function() {
echo 'what should I do?';
})->addEndingMessage('THE END');//outputs: ok fine - what should I do? - THE END