IT.COM

Memory Management with PHP's Declare

Spaceship Spaceship
Watch
Impact
4
Advanced PHP: Memory Management with PHP's Declare

I'm sure it's happened with the best of us. A script suddenly gets stuck in a loop and saps all the memory from the server. However, aside from programmer-induced loops, memory errors can also be a good way for a hacker to gain insightful information in to the way your application is setup.

Not only that, but it'd be really nice to monitor how much memory your scripts are consuming, would it not? This is where declare steps into the door way and makes its presence felt.

The declare construct allows you to execute a function every so many ticks. A tick is loosely defined as every line a low level action takes place. Thus when a mathematical equation takes place, or a value being assigned to a variable - even a curly brace to end if or while statements is considered a tick.

A simple tick can be setup like so:

PHP:
function talkphp_example()
{
	echo 'TalkPHP is the place to be for PHP discussions.<br />';
}

register_tick_function('talkphp_example');

declare(ticks = 1)
{
	$iA = 1;
	$iB = $iA * 4.5;
	$iC = ($iB / $iA) * 8;
}

The 2 lines you may not be familiar with are the following:

  • register_tick_function: Specifies the function to call on every tick.
  • declare(ticks = 1): Declared for the block of code that follows as indicated by the curly braces. The ticks specifies the amount of lines to wait for before executing the tick register function, in our case talkphp_example.

Putting it to some use

The usefulness of declare may not be apparent immediately. However, it has some nice advantages when you wish to monitor something. Such as in our case, memory management. There are some other purposes I've thought of (or, in admission, read about):

  • Memory management
  • CPU Management
  • Sustain Database Connection
  • Flow Control Management (Using __LINE__)

Let's take a look at our memory management function for the declare construct:

PHP:
define('MEMORY_MAX', 50000); // Bytes
	
function memory_profiler($bReturn = false)
{
	static $iMemory = 0;
	
	if($bReturn)
	{
		return $iMemory . ' bytes';
	}
	
	if(($iTmpMemory = memory_get_usage()) > $iMemory)
	{
		if($iTmpMemory >= MEMORY_MAX)
		{
			die('Consumed too much memory');
		}
		
		$iMemory = $iTmpMemory;
	}
}

This will keep a tab on the memory being consumed by the script and die when the script consumes too much as specified by the define. Although PHP, by default, may consume 8 megabytes - this is rather a lot and somewhat unnecessary for any non-GD or any other server intensive actions.

We then specify our tick function as well as our declare construct for the chunk of code we wish to monitor:

PHP:
register_tick_function('memory_profiler');

declare(ticks = 1)
{
	$szText = 'We adore TalkPHP.com';
	$szText = str_replace('We', 'I', $szText);
	$szText = $szText . '!';
}

Once you have done this the tick function will be called 4 times:

  • Tick 1: $szText = 'We adore TalkPHP.com';
  • Tick 2: $szText = str_replace('We', 'I', $szText);
  • Tick 3: $szText = $szText . '!';
  • Tick 4: }

Any programming outside of the declare block will not count towards our memory management handling. Thus to make the declare global we would use the declare construct like so:

PHP:
declare(ticks = 1);

$iA = 1;
$iB = $iA * 4.5;
$iC = ($iB / $iA) * 8;

To display the total amount of memory our script sucked from our system like a blood-hungry vampire, we can display it at the bottom using the following:

PHP:
echo memory_profiler(true);

Instead of the unfriendly die, a header may be a more user-friendly way to inform the user something unexpected has occurred and the script is consuming too much memory. This can be done like so:

PHP:
header('location: http://www.talkphp.com/memory_limit.html');
exit();

Note: Don't forget to use a FQDN (fully qualified domain name) in the header() as it's a new request entirely. Also, do not forget to specify to exit the script after the header. The header is sent to the client but it's entirely up to the browser to act on the header issued.

Performance Concerns and Closure

Just remember that calling this function inside a declare is a nice addition, but keep in mind the performance issues that may arise if your tick function contains server intensive actions. The declare function can be exceedingly powerful for absolutely all sorts of various things. Your task for today? Dream up some weird and wonderful uses and get back to us!
 
Last edited:
1
•••
The views expressed on this page by users and staff are their own, not those of NamePros.
Good post, I never knew about declare();
 
0
•••
Thanks. It's definitely a new one. I've only known about it for the best part of 2 months. It's been an excellent addition to many of my scripts.
 
0
•••
new to me as well thanks :D
 
0
•••
  • The sidebar remains visible by scrolling at a speed relative to the page’s height.
Back