Sunday, August 12. 2012
The slides from my talk, Caching with Memcached are now available and can be downloaded here: http://ilia.ws/files/nena_memcached.pdf.
Thanks for everyone who attended and asked questions, wish we had a bit more time to allow for more questions, but if anything was left un-answered come find me or post your questions on this blog.
P.S. If you've seen the talk please don't forget to leave feedback at Joind.in.
Saturday, August 11. 2012
The slides from my talk, introducing PHP 5.4 are now available and can be downloaded here: http://ilia.ws/files/nena_php54.pdf.
Thanks for all the attendees for being a wonderful audience, especially those asking many great questions.
P.S. If you've seen the talk please don't forget to leave feedback at Joind.in.
Wednesday, June 6. 2012
The slides from my presentation at PHP-GTA about the Hidden Features of PHP is now available online and can be downloaded here: http://ilia.ws/files/php-toronto_hidden_features.pdf. Hopefully everyone in attendance learned something new about PHP and many thanks to all the people who had asked questions helped make the discussion that much more interesting.
Sunday, June 3. 2012
For our database connections we PDO at work and we've extended the class with PHP to offer some other convenience functionality and wrappers. One of the things I wanted to do recently is allow the constructor of the PDO class to fail-over to our backup database connection pool in the event the primary was not available. The idea was to do something along the lines of:
PHP:
<?php
class DB extends PDO {
public function __construct($dsn, $login, $pass, $backup_dsn) {
try {
parent::__construct($dsn, $login, $pass);
} catch (Exception $e) {
parent::__construct($backup_dsn, $login, $pass);
}
}
}
?>
Essentially the code would call the PDO's own constructor, if it would fail, an exception would be raised, which would then be caught by the exception handler that will attempt to connect to the backup database connection pool. Unfortunately this simple solution does not work, the reason being, is that when PDO's constructor fails to connect, it destroys the object. Which means any attempts to use or access the object fail, even $this is equal to NULL, effectively making the 2nd construct call pointless.
While this behaviour makes sense on most cases, in some cases such as a fallback scenario illustrated above this is an undesired behaviour. To address this limitation I've written a small patch (http://ilia.ws/patch/pdo.txt) which introduces a PDO:: ATTR_KEEP_CLASS_CONN_FAILURE configuration option that can be passed to PDO's constructor, telling it to keep the object alive after a failed attempt to connect to the database, allowing re-connection to be attempted. With this patch in place, the above code can be implemented as per example below.
PHP:
<?php
class DB extends PDO {
public function __construct($dsn, $login, $pass, $backup_dsn) {
try {
parent::__construct($dsn, $login, $pass, array(PDO:: ATTR_KEEP_CLASS_CONN_FAILURE => 1));
} catch (Exception $e) {
parent::__construct($backup_dsn, $login, $pass);
}
}
}
?>
Saturday, March 3. 2012
At Confoo I had an interesting conversation with Guilherme Blanco regarding the fact that in Doctrine 2 they had a performance issue due to usage of array_key_exists() and how it was significantly slower than isset(). His anecdotal example was that doing isset() took 0.5 seconds, while array_key_exists() for the same operation took 5 seconds!
That seemed wrong, given that array_key_exists() simply does a hash table look-up, to determine if the array key exists and the only speed difference would be due to the fact that isset() is a language construct and does not have the overhead of function & parameter processing. So, I've decided to do a quick benchmark using a 5,000 element array.
PHP:
<?php
$arr = array();
$fp = fopen("/usr/share/dict/words", "r");
while ($i < 5000 && ($w = fgets($fp))) {
$arr[trim($w)] = ++$i;
}
$s = microtime(1);
for ($i = 0; $i < 100000; $i++) {
isset($arr['abracadabra']);
}
$e = microtime(1);
echo "Isset: ".($e - $s)."\n";
$s = microtime(1);
for ($i = 0; $i < 100000; $i++) {
array_key_exists('abracadabra', $arr);
}
$e = microtime(1);
echo "array_key_exists: ".($e - $s)."\n";
?>
The above benchmark executed on PHP 5.4 shows that while isset() is 2.5 times faster taking a mere 0.0219 seconds vs 0.0549 seconds taken by array_key_exists(), both operations are extremely quick and take a fraction of a second even when doing 100k operations. Any "optimization" between the calls is purely within the super-micro-micro optimization realm and is not going to make any application measurably faster.
The bottom line is that if your application does not need to distinguish between an array key that does not exist and one whose value happens to be NULL you should use isset() because it happens to be a little faster. However, if a NULL array key value and a non-existant array key are something you need to differentiate between, use array_key_exists() and you don't need to worry about the performance, the function is extremely fast, even in the case of Doctrine 2 that apparently may do as many as 50,000 calls to the function per-request in some cases.
Friday, March 2. 2012
My slides from the Confoo presentation on PHP 5.4 are up and can be viewed/downloaded from here:
http://ilia.ws/files/confoo_php54.pdf
I look forward to everyone's feedback either on this blog or via Joind.in.
And in case you didn't know, PHP 5.4 was released yesterday!
[Update March 3, 2012]
Based on great suggestion from Rasmus, I've updated the charset slide to clarify that the change introduced in 5.4 relates to the default charset used by internal entities functions (htmlspecialchars, htmlentities, etc...) and updating the default_charset INI is one of the changes you may need to do to account for this change.
Wednesday, February 29. 2012
The slides from my "Introduction to PostgreSQL" talk at Confooare now available for view/download
and can found here: http://ilia.ws/files/confoo_pgsql.pdf. Hopefully it will make people more interested in PostgreSQL, which is a great database system and take it into consideration when making their database platform decisions.
For me personally, it was quite interesting, as it is one of the rare chances I get to speak about something that is not directly related to PHP, although I did sneak-in a few PHP specific slides
I would very much appreciate feedback from all who had attended the talk and any suggestions on how to make it better are always welcome. Please send me your comments via this blog or via Joind.in.
A big thanks for to Bruce Momjian from Enterprise DB who gave me some really good suggestions on improving the slides (already reflected in the PDF) and Christophe Pettus from PostgreSQL Experts, Inc. whose original PostgreSQL Intro talk had inspired mine.
Wednesday, December 7. 2011
While profiling our application I came across a a rather strange memory usage by the ob_start() function. We do use ob_start() quite a bit to defer output of data, which is a common thing in many applications. What was unusual is that 16 calls to ob_start() up chewing through almost 700kb of memory, given that the data being buffered rarely exceeds 1-2kb, this was quite unusual.
I started looking at the C code of the ob_start() function and found this interesting bit of code inside php_start_ob_buffer()
initial_size = 40*1024;
block_size = 10*1024;
Which directs PHP to pre-allocate 40kb of data for each ob_start() call and when this proves to be insufficient, increase by 10kb each time. Ouch!
PHP does allow you to say how much memory ob_start() can use, via 2nd parameter to the function. However, if you exceed that size, PHP will promptly flush the captured data to screen, which means that unless you are really good at predicting your buffer sizes or vastly overestimate, there is a risk that the data will be dumped to screen by PHP if you use this option.
Since I am not really good at guessing, I've decided to make a small, backwards compatible tweak to PHP's code that allow specification of custom buffer sizes, but allow the buffer size to be increased if the initial buffer size proves to be insufficient, ensuring that the data can be safely buffered. This functionality is implemented through a change (see patch below) to the 1st parameter of the ob_start() function, which normally is used to provide the callback function. With the patch in place the parameter, can be a number, which defines the desired buffer size. With the patch, ob_start(1024) means that the 1kb buffer should be used and when it is exceed keep allocating 1kb at a time to allow for additional data to be stored. This solution does mean you cannot use custom, resizable buffer sizes with a callback function, however it does provider a backwards (PHP API wise) compatible way of implementing the functionality in PHP 5.2 and 5.3.
Here is a simple before & after example:
PHP:
<?php
ob_start(null, 1024);
echo str_repeat("a", 1500);
var_dump(strlen(ob_get_clean()));
?>
will print 0, since buffer is exceeded and is flushed to screen
PHP:
<?php
ob_start(1024);
echo str_repeat("a", 1500);
var_dump(strlen(ob_get_clean()));
?>
will print 1500, buffer was exceeded and subsequently increased, allowing data to remain in the buffer
CODE: Index: main/output.c
===================================================================
--- main/output.c (revision 320624)
+++ main/output.c (working copy)
@@ -155,10 +155,14 @@
initial_size = (chunk_size*3/2);
block_size = chunk_size/2;
} else {
- initial_size = 40*1024;
- block_size = 10*1024;
+ if (output_handler && Z_TYPE_P(output_handler) == IS_LONG && !chunk_size) {
+ initial_size = block_size = Z_LVAL_P(output_handler);
+ } else {
+ initial_size = 40*1024;
+ block_size = 10*1024;
+ }
}
- return php_ob_init(initial_size, block_size, output_handler, chunk_size, erase TSRMLS_CC);
+ return php_ob_init(initial_size, block_size,
+ (output_handler && Z_TYPE_P(output_handler) != IS_LONG ? output_handler : NULL),
+ chunk_size, erase TSRMLS_CC);
}
/* }}} */
Tuesday, October 18. 2011
My slides for my "Under the Hood" talk at ZendCon are now online and can be downloaded here.
Thanks to all the attendees, especially those who left feedback at Joind.In.
Wednesday, August 3. 2011
I've just released a new version of php-excel extension that exposes the new functionality offered by libxl 3.2.0.
The new functionality in this release includes the following:
- ExcelSheet::setPrintFit(int wPages, int hPages) that fits sheet width and sheet height to wPages and hPages respectively
- ExcelSheet::getPrintFit() that returns whether fit to page option is enabled, and if so to what width & height
- ExcelSheet::getNamedRange(string name) that gets the named range coordianates by name, returns false if range is not found
- ExcelSheet::getIndexRange(int index) that gets the named range coordianates by index, returns false if range is not found
- ExcelSheet::namedRangeSize() that returns the number of named ranges in the sheet
- ExcelSheet::getVerPageBreak(int index) that returns column with vertical page break at position index
- ExcelSheet::getVerPageBreakSize() that returns a number of vertical page breaks in the sheet
- ExcelSheet::getHorPageBreak(int index) that eturns column with horizontal page break at position index
- ExcelSheet::getHorPageBreakSize() that returns a number of horizontal page breaks in the sheet
- ExcelSheet::getPictureInfo(int index) that returns a information about a workbook picture at position index in worksheet
- ExcelSheet::getNumPictures() that returns a number of pictures in this worksheet
- ExcelBook::biffVersion() that returns BIFF version of binary file. (Used for xls format only)
- ExcelBook::getRefR1C1() that returns whether the R1C1 reference mode is active
- ExcelBook::setRefR1C1(bool active) that sets the R1C1 reference mode
- ExcelBook::getPicture(int picture_index) that returns a picture at position index
- ExcelBook::getNumPictures() that returns a number of pictures in this workbook
- ExcelSheet ExcelBook::insertSheet(int index, string name [, ExcelSheet sh]) that inserts a new sheet to this book at position index,
returns the sheet handle. If ExcelSheet parameter is missing a new sheet will be created.
The source code & tar balls can be found at https://github.com/iliaal/php_excel
Wednesday, June 1. 2011
The slides from my talk on the Hidden Features of PHP are now available and can be downloaded from here:
ipc_2011_hidden_features.pdf
Thanks to all the people who attended the talk and I really am looking for your feedback via Joind.in.
Tuesday, May 31. 2011
The slides from my talk on the Memcached extension are now available and can be downloaded from here:
ipc_Memcached_2011.pdf
Thanks to all the people who attended the talk and I really am looking for your feedback via Joind.in.
Friday, March 11. 2011
My slides for the "Hidden PHP Features" talk at ConFoo are now available at http://ilia.ws/files/confoo_2011_hidden_features.pdf.
If you were at the talk, please give me your feedback/suggestions at: http://joind.in/2905.
Thursday, March 10. 2011
Thanks to all the people who attended my talk on the APC and Memcached yesterday at Confoo. The slides are now available to download at: http://ilia.ws/files/confoo_APC_MEM2011.pdf
If you have any feedback, or comments they would be much appreciated via Joind.In ( http://joind.in/2806)
Tuesday, January 18. 2011
The 0.9.1 version of the Excel extension was released and is now available for download. This is mostly a bug fix release, with a number of contributions by Rob Gagnon. The 2 main fixes are related to detection of custom formatted numeric fields, that were incorrectly detected as dates and readRow()/readCol() methods that had a bug when 2 and 3rd parameters are supplied, causing the last row/column not to be read. Additionally a getSheetByName() method was introduced that allows locating a sheet by it's name in either case sensitive or insensitive form.
GitHub: http://github.com/iliaal/php_excel/
Source: http://github.com/downloads/iliaal/php_excel/php-excel-0.9.1.tar.bz2
|