CINXE.COM

Still trying to get it all out: June 2006

<!DOCTYPE html> <html dir='ltr'> <head> <link href='https://www.blogger.com/static/v1/widgets/55013136-widget_css_bundle.css' rel='stylesheet' type='text/css'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='http://blog.golemon.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://blog.golemon.com/2006/06/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Still trying to get it all out - Atom" href="http://blog.golemon.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Still trying to get it all out - RSS" href="http://blog.golemon.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Still trying to get it all out - Atom" href="https://www.blogger.com/feeds/1234953837283832282/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://blog.golemon.com/2006/06/' property='og:url'/> <meta content='Still trying to get it all out' property='og:title'/> <meta content='' property='og:description'/> <title>Still trying to get it all out: June 2006</title> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Minima Date: 26 Feb 2004 Updated by: Blogger Team ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="bgcolor" description="Page Background Color" type="color" default="#fff"> <Variable name="textcolor" description="Text Color" type="color" default="#333"> <Variable name="linkcolor" description="Link Color" type="color" default="#58a"> <Variable name="pagetitlecolor" description="Blog Title Color" type="color" default="#666"> <Variable name="descriptioncolor" description="Blog Description Color" type="color" default="#999"> <Variable name="titlecolor" description="Post Title Color" type="color" default="#c60"> <Variable name="bordercolor" description="Border Color" type="color" default="#ccc"> <Variable name="sidebarcolor" description="Sidebar Title Color" type="color" default="#999"> <Variable name="sidebartextcolor" description="Sidebar Text Color" type="color" default="#666"> <Variable name="visitedlinkcolor" description="Visited Link Color" type="color" default="#999"> <Variable name="bodyfont" description="Text Font" type="font" default="normal normal 100% Georgia, Serif"> <Variable name="headerfont" description="Sidebar Title Font" type="font" default="normal normal 78% 'Trebuchet MS',Trebuchet,Arial,Verdana,Sans-serif"> <Variable name="pagetitlefont" description="Blog Title Font" type="font" default="normal normal 200% Georgia, Serif"> <Variable name="descriptionfont" description="Blog Description Font" type="font" default="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif"> <Variable name="postfooterfont" description="Post Footer Font" type="font" default="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif"> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"> */ /* Use this with templates/template-twocol.html */ body { background:#ffffff; margin:0; color:#333333; font:x-small Georgia Serif; font-size/* */:/**/small; font-size: /**/small; text-align: center; } a:link { color:#5588aa; text-decoration:none; } a:visited { color:#999999; text-decoration:none; } a:hover { color:#cc6600; text-decoration:underline; } a img { border-width:0; } /* Header ----------------------------------------------- */ #header-wrapper { width:960px; margin:0 auto 10px; border:1px solid #cccccc; } #header-inner { background-position: center; margin-left: auto; margin-right: auto; } #header { margin: 5px; border: 1px solid #cccccc; text-align: center; color:#666666; } #header h1 { margin:5px 5px 0; padding:15px 20px .25em; line-height:1.2em; text-transform:uppercase; letter-spacing:.2em; font: normal normal 200% Georgia, Serif; } #header a { color:#666666; text-decoration:none; } #header a:hover { color:#666666; } #header .description { margin:0 5px 5px; padding:0 20px 15px; max-width:700px; text-transform:uppercase; letter-spacing:.2em; line-height: 1.4em; font: normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif; color: #999999; } #header img { margin-left: auto; margin-right: auto; } /* Outer-Wrapper ----------------------------------------------- */ #outer-wrapper { width: 960px; margin:0 auto; padding:10px; text-align:left; font: normal normal 100% Georgia, Serif; } #main-wrapper { width: 710px; float: left; word-wrap: break-word; /* fix for long text breaking sidebar float in IE */ overflow: hidden; /* fix for long non-text content breaking IE sidebar float */ } #sidebar-wrapper { width: 220px; float: right; word-wrap: break-word; /* fix for long text breaking sidebar float in IE */ overflow: hidden; /* fix for long non-text content breaking IE sidebar float */ } /* Headings ----------------------------------------------- */ h2 { margin:1.5em 0 .75em; font:normal normal 78% 'Trebuchet MS',Trebuchet,Arial,Verdana,Sans-serif; line-height: 1.4em; text-transform:uppercase; letter-spacing:.2em; color:#999999; } /* Posts ----------------------------------------------- */ h2.date-header { margin:1.5em 0 .5em; } .post { margin:.5em 0 1.5em; border-bottom:1px dotted #cccccc; padding-bottom:1.5em; } .post h3 { margin:.25em 0 0; padding:0 0 4px; font-size:140%; font-weight:normal; line-height:1.4em; color:#cc6600; } .post h3 a, .post h3 a:visited, .post h3 strong { display:block; text-decoration:none; color:#cc6600; font-weight:normal; } .post h3 strong, .post h3 a:hover { color:#333333; } .post-body { margin:0 0 .75em; line-height:1.6em; } .post-body blockquote { line-height:1.3em; } .post-footer { margin: .75em 0; color:#999999; text-transform:uppercase; letter-spacing:.1em; font: normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif; line-height: 1.4em; } .comment-link { margin-left:.6em; } .post img, table.tr-caption-container { padding:4px; border:1px solid #cccccc; } .tr-caption-container img { border: none; padding: 0; } .post blockquote { margin:1em 20px; } .post blockquote p { margin:.75em 0; } /* Comments ----------------------------------------------- */ #comments h4 { margin:1em 0; font-weight: bold; line-height: 1.4em; text-transform:uppercase; letter-spacing:.2em; color: #999999; } #comments-block { margin:1em 0 1.5em; line-height:1.6em; } #comments-block .comment-author { margin:.5em 0; } #comments-block .comment-body { margin:.25em 0 0; } #comments-block .comment-footer { margin:-.25em 0 2em; line-height: 1.4em; text-transform:uppercase; letter-spacing:.1em; } #comments-block .comment-body p { margin:0 0 .75em; } .deleted-comment { font-style:italic; color:gray; } #blog-pager-newer-link { float: left; } #blog-pager-older-link { float: right; } #blog-pager { text-align: center; } .feed-links { clear: both; line-height: 2.5em; } /* Sidebar Content ----------------------------------------------- */ .sidebar { color: #666666; line-height: 1.5em; } .sidebar ul { list-style:none; margin:0 0 0; padding:0 0 0; } .sidebar li { margin:0; padding-top:0; padding-right:0; padding-bottom:.25em; padding-left:15px; text-indent:-15px; line-height:1.5em; } .sidebar .widget, .main .widget { border-bottom:1px dotted #cccccc; margin:0 0 1.5em; padding:0 0 1.5em; } .main .Blog { border-bottom-width: 0; } /* Profile ----------------------------------------------- */ .profile-img { float: left; margin-top: 0; margin-right: 5px; margin-bottom: 5px; margin-left: 0; padding: 4px; border: 1px solid #cccccc; } .profile-data { margin:0; text-transform:uppercase; letter-spacing:.1em; font: normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif; color: #999999; font-weight: bold; line-height: 1.6em; } .profile-datablock { margin:.5em 0 .5em; } .profile-textblock { margin: 0.5em 0; line-height: 1.6em; } .profile-link { font: normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif; text-transform: uppercase; letter-spacing: .1em; } /* Footer ----------------------------------------------- */ #footer { width:660px; clear:both; margin:0 auto; padding-top:15px; line-height: 1.6em; text-transform:uppercase; letter-spacing:.1em; text-align: center; } --></style> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=1234953837283832282&amp;zx=49467963-e08e-4f27-9dd9-074a1d6bc25d' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=1234953837283832282&amp;zx=49467963-e08e-4f27-9dd9-074a1d6bc25d' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body> <div class='navbar section' id='navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar/1234953837283832282?origin\x3dhttp://blog.golemon.com', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script><script type="text/javascript"> (function() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js'; var head = document.getElementsByTagName('head')[0]; if (head) { head.appendChild(script); }})(); </script> </div></div> <div id='outer-wrapper'><div id='wrap2'> <!-- skip links for text browsers --> <span id='skiplinks' style='display:none;'> <a href='#main'>skip to main </a> | <a href='#sidebar'>skip to sidebar</a> </span> <div id='header-wrapper'> <div class='header section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner'> <div class='titlewrapper'> <h1 class='title'> <a href='http://blog.golemon.com/'> Still trying to get it all out </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span> </span></p> </div> </div> </div></div> </div> <div id='content-wrapper'> <div id='crosscol-wrapper' style='text-align:center'> <div class='crosscol no-items section' id='crosscol'></div> </div> <div id='main-wrapper'> <div class='main section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <h2 class='date-header'><span>Jun 18, 2006</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='1234953837283832282' itemprop='blogId'/> <meta content='6618893132754240091' itemprop='postId'/> <a name='6618893132754240091'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://blog.golemon.com/2006/06/how-long-is-piece-of-string.html'>How long is a piece of string</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6618893132754240091' itemprop='description articleBody'> <div><span><p>Sunday morning I was asked by an IRC regular: "Where does the engine parse quoted strings?". Being a sunday morning, I began to launch into a sermon on the distinction between <span style="font-family:courier;">CONSTANT_ENCAPSED_STRING</span> and the problems which befall a single-pass compiler when you start to introduce interpolation. Not what he asked precisely, but an important component in answering his question. Unfortunately, at the time I was busy watching the Brasil-Australia game so I didn't go into the kind of detail I would have. Now, some 12 hours later, since Angela is off buying toe-socks in Santa Cruz, I'll bore anyone with little enough life to read my blog by explaining the pitfalls of using PHP's string interpolation without using an optimizer.</p></span><div><p>To start things off, let's take a page from my earlier discourse on <a href="http://saragolemon.blogspot.com/2006/05/last-month-at-phptek-i-gave.html">Compiled Variables</a> and look at the opcodes generated by a few simple PHP scripts:</p><blockquote><pre style="font-family:courier new;font-size:78%;line-spacing:0">&lt;?php<br />echo "This is a constant string";<br />?&gt;<br /></pre></blockquote><br /><p>Yields the nice, simple opcode:</p> <blockquote><pre style="font-family:courier new;font-size:78%;">ECHO 'This is a constant string'<br /></pre></blockquote> <p>No problem... Exactly what you'd expect... Now let's complicate the expressions a little:</p> <blockquote><pre><span style="font-family:courier new;font-size:78%;">&lt;?php</span><span style="font-size:78%;"><br /></span><span style="font-family:courier new;font-size:78%;">echo "This is an interpolated $string";</span><span style="font-size:78%;"><br /></span><span style="font-family:courier new;font-size:78%;">?&gt;</span><br /></pre></blockquote> <p>Yields the surprisingly messy instruction set:</p> <blockquote><pre style="font-family:courier new;font-size:78%;">INIT STRING ~0<br />ADD_STRING ~0 ~0 'This'<br />ADD_STRING ~0 ~0 ' '<br />ADD_STRING ~0 ~0 'is'<br />ADD_STRING ~0 ~0 ' '<br />ADD_STRING ~0 ~0 'an'<br />ADD_STRING ~0 ~0 ' '<br />ADD_STRING ~0 ~0 'interpolated'<br />ADD_STRING ~0 ~0 ' '<br />ADD_VAR ~0 ~0 !0<br />ECHO ~0<br /></pre></blockquote> <p>Where !0 represents the compiled variable named <span style="font-family:courier;">$string</span>. Looking at these opcodes: <span style="font-family:courier;">INIT_STRING</span> allocates an <span style="font-family:courier;">IS_STRING</span> variable of one byte (to hold the terminating <span style="font-family:courier;">NULL</span>). Then it's realloc'd to five bytes by the first <span style="font-family:courier;">ADD_STRING</span> ('This' plus the terminating <span style="font-family:courier;">NULL</span>). Next it's realloc'd to six bytes in order to add a space, then again to eight bytes for 'is', then nine to add a space, and so on until the temporary string has the contents of the interpolated variable copied into its contents before being used by the echo statement and finally discarded. Now let's rewrite that line to avoid interpolation and use concatenation instead:</p> <blockquote><pre style="font-family:courier new;font-size:78%;">&lt;?php<br />echo "This is a concatenated " . $string;<br />?&gt;<br /></pre></blockquote> <p>Which yields the significantly shorter and simpler set of ops:</p> <blockquote><pre style="font-family:courier new;font-size:78%;">CONCAT ~0 'This is a concatenated ' !0<br />ECHO ~0<br /></pre></blockquote> <p>A vast improvement already, but this version still creates a temporary <span style="font-family:courier;">IS_STRING</span> variable to hold the combined string contents meaning that data is duplicated when it's being used in a <span style="font-family:courier;">const</span> context anyway. Now let's try out this oft-overlooked use of the echo statement:</p> <blockquote><pre><span style="font-family:courier new;font-size:85%;">&lt;?php</span><span style="font-size:85%;"><br /></span><span style="font-family:courier new;font-size:85%;">echo "This is a stacked echo " , $string;</span><span style="font-size:85%;"><br /></span><span style="font-family:courier new;font-size:85%;">?&gt;</span><br /></pre></blockquote> <p>Look close, there is a meaningful difference from the last one. This time we're using a comma rather than a dot between the operands. If you don't know what the comma is doing there, ask <a href="http://www.php.net/echo">the manual</a> then check back here. Here's the resulting opcodes:</p> <blockquote><pre><span style="font-family:courier new;font-size:78%;">ECHO 'This is a stacked echo '</span><span style="font-size:78%;"><br /></span><span style="font-family:courier new;font-size:78%;">ECHO !0</span><br /></pre></blockquote><p>Same number of opcodes, but this time no temporary variables are being created so there's no duplication and no pointless copying (unless of course <span style="font-family:courier;">$string</span> wasn't of type <span style="font-family:courier;">IS_STRING</span>, in which case it does have to be converted for output, but don't get picky now). Think this is bad? Consider the average heredoc string which spans several lines of prepared output embedding perhaps a handful of variables along the way. Here's one of several such blocks found in <span style="font-family:courier;">run-tests.php</span> within the PHP distribution source tree:</p> <br /><blockquote><pre style="font-family:courier new;font-size:78%;">&lt;?php<br />echo &lt;&lt;NO_PCRE_ERROR<br /><br />+-----------------------------------------------------------+<br />| ! ERROR ! |<br />| The test-suite requires that you have pcre extension |<br />| enabled. To enable this extension either compile your PHP |<br />| with --with-pcre-regex or if you've compiled pcre as a |<br />| shared module load it via php.ini. |<br />+-----------------------------------------------------------+<br /><br />NO_PCRE_ERROR;<br />?&gt;<br /></pre></blockquote> <br /><p>Notice that we're not even embedding variables to be interpolated here, yet does this come out to a simple, single opcode? Nope, because the rules necessary to catch a heredoc's end token demand the same careful examination as double-quoted variable substitution and you wind up (in this case) with SEVENTY-EIGHT opcodes! One <span style="font-family:courier;">INIT_STRING</span>, 76 <span style="font-family:courier;">ADD_STRING</span>s. and a final <span style="font-family:courier;">ECHO</span>. That means a malloc, 76 reallocs, and a free which will be executed every time that code snippet comes along. Even the original contents take up more memory because they're stored in 76 distinct zval/<span style="font-family:courier;">IS_STRING</span> structures.</p><p>Why does this happen? Because there are about a dozen ways that a variable can be hidden inside an interpolated string. Similarly, when looking for a heredoc end-token, the token can be an arbitrary length, containing any of the label characters, and may or may not sit on a line by itself. Put simply, it's too difficult to encompass in one regular expression.</p> <p>The engine <i>could</i> perform a second-pass during compilation, however the time saved reassembling these strings will typically be about the same amount of time spent actually processing them during runtime (if one assumes that each instance will execute exactly once). Rather than complicate the build process (potentially slowing down overall run-times in the process), the compiler leaves this optimization step to opcode caches which can achieve exponentially greater advantage cleaning up this mess then caching the results and reusing the faster, leaner versions on all subsequent runs.</p><p>If you're using <a href="http://pecl.php.net/package/apc">APC</a>, you'll find just such an optimizer built in, but not enabled by default. To turn it on, you'll need to set <span style="font-family:courier;">apc.optimization=on</span> in your php.ini. In addition to stitching these run-on opcodes back together, it'll also add run-time speed-ups like pre-resolving persistent constants to their actual values, folding static scalar expressions (like 1 + 1) to their fixed results (e.g. 2), and simpler stuff like avoiding the use of JMP when the target is the next opcode, or boolean casts when the original expression is known to be a boolean value. (It should be noted that these speed-ups also break some of the runtime-manipulation features of <a href="http://pecl.php.net/package/runkit">runkit</a>, but that was stuff you....probably should have been doing anyway)</p><p>Can't use an optimizer because your webhost doesn't know how to set php.ini options? You can still avoid 90% of the <span style="font-family:courier;">INIT_STRING</span>/<span style="font-family:courier;">ADD_STRING</span> dilema by simply using single quotes and concatenation (or commas when dealing with echo statements). It's a simple trick and one which shouldn't harm maintainability too much, but on a large, complicated script, you just might see an extra request or two per second.</p><br /></div></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/14557640555210645219' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/14557640555210645219' rel='author' title='author profile'> <span itemprop='name'>Sara Golemon</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://blog.golemon.com/2006/06/how-long-is-piece-of-string.html' itemprop='url'/> <a class='timestamp-link' href='http://blog.golemon.com/2006/06/how-long-is-piece-of-string.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2006-06-18T19:05:00-07:00'>19:05</abbr></a> </span> <span class='post-comment-link'> <a class='comment-link' href='http://blog.golemon.com/2006/06/how-long-is-piece-of-string.html#comment-form' onclick=''> 1 comment: </a> </span> <span class='post-icons'> <span class='item-control blog-admin pid-950715124'> <a href='https://www.blogger.com/post-edit.g?blogID=1234953837283832282&postID=6618893132754240091&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=6618893132754240091&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=6618893132754240091&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=6618893132754240091&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=6618893132754240091&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=6618893132754240091&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='http://blog.golemon.com/search/label/php' rel='tag'>php</a>, <a href='http://blog.golemon.com/search/label/strings' rel='tag'>strings</a>, <a href='http://blog.golemon.com/search/label/zend' rel='tag'>zend</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Jun 7, 2006</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://farm1.static.flickr.com/75/174928046_e59eef7e6d_o.jpg' itemprop='image_url'/> <meta content='1234953837283832282' itemprop='blogId'/> <meta content='4489018663909033530' itemprop='postId'/> <a name='4489018663909033530'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://blog.golemon.com/2006/06/extending-and-embedding-php.html'>Extending and Embedding PHP</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4489018663909033530' itemprop='description articleBody'> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm1.static.flickr.com/75/174928046_e59eef7e6d_o.jpg"><img alt="" border="0" src="http://farm1.static.flickr.com/75/174928046_e59eef7e6d_o.jpg" style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 154px; height: 113px;" /></a><br /><span class="entry-summary">It's official!!!! After a year in development Extending and Embedding PHP is now shipping from fine book stores everywhere.<br /><p><a href="http://blog.libssh2.org/uploads/eephp_stack.jpg" target="_new"><br /></a></p> <p>I've gotten good reviews from the half dozen people I know who've gotten their hands on it, and I <i>am</i> really satisfied with most of it. Do I think it could be better? Of course I do, but I don't think I was ever going to be completely satisfied.</p><br /><p>I've learned a lot through this process and while I don't see any more titles in my immediate future (there are things coming down the pipe which are likely to change my availability), I do expect that my next book, should it materialize, will be even better.</p><br /><p>If you pre-ordered it, you should see it soon, if you've already got your copy, let me know what you think! Did I skim over some topic too quickly? Did I belabour something else? If this book eventually finds it's way into a 2<sup>nd</sup> edition (no promises mind you), are there topics you want to see added? Tossed out? Expanded/Compressed?</p></span> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/14557640555210645219' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/14557640555210645219' rel='author' title='author profile'> <span itemprop='name'>Sara Golemon</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://blog.golemon.com/2006/06/extending-and-embedding-php.html' itemprop='url'/> <a class='timestamp-link' href='http://blog.golemon.com/2006/06/extending-and-embedding-php.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2006-06-07T14:20:00-07:00'>14:20</abbr></a> </span> <span class='post-comment-link'> <a class='comment-link' href='http://blog.golemon.com/2006/06/extending-and-embedding-php.html#comment-form' onclick=''> 1 comment: </a> </span> <span class='post-icons'> <span class='item-control blog-admin pid-950715124'> <a href='https://www.blogger.com/post-edit.g?blogID=1234953837283832282&postID=4489018663909033530&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=4489018663909033530&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=4489018663909033530&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=4489018663909033530&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=4489018663909033530&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=4489018663909033530&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='http://blog.golemon.com/search/label/book' rel='tag'>book</a>, <a href='http://blog.golemon.com/search/label/php' rel='tag'>php</a>, <a href='http://blog.golemon.com/search/label/win' rel='tag'>win</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Jun 1, 2006</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='1234953837283832282' itemprop='blogId'/> <meta content='2778191266369728679' itemprop='postId'/> <a name='2778191266369728679'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html'>What the heck is TSRMLS_CC, anyway?</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-2778191266369728679' itemprop='description articleBody'> <span class="entry-content"><p>If you've ever worked on the PHP internals or built an extension, you've seen this construct floating around here and there, but noone ever talks about it. Those who know what this is typically answer questions from those who don't with "Don't worry about what it is, just use it here here here and here. And if the compiler says you're missing a <span style="font-family: courier;">tsrm_ls</span>, put it there too..." This isn't laziness on the part of the person answering the question (okay, maybe it is a little bit), it's just that the engine goes so far out of its way to simplify what this magic values does, that there's no profit in a new extension developer knowing the mechanics of it. The information is like a cow's opinion, it doesn't matter, it's Moo.</p><br /><p>Since I love to listen to myself rattle on about pointless topics (and I havn't blogged much this month), I thought I'd cover this topic and see if anyone manages to stay awake through it. You can blame Lukas, he got me rolled onto planet-php.net...</p></span> <h3>Glossary</h3> <div class="serendipity_entry_extended"><dt>TSRM</dt> <dd><b>T</b>hread <b>S</b>afe <b>R</b>esource <b>M</b>anager - This is an oft overlooked, and seldom if ever discussed layer hiding in the /TSRM directory of your friendly neighborhood PHP source code bundle. By default, the TSRM layer is only enabled when compiling a SAPI which requires it (e.g. apache2-worker). All Win32 builds have this layer enabled enabled regardless of SAPI choice.</dd><br /><br /><dt>ZTS</dt> <dd><b>Z</b>end <b>T</b>hread <b>S</b>safety - Often used synonymously with the term <i>TSRM</i>. Specifically, ZTS is the term used by <span style="font-family: courier;">./configure</span> ( <span style="font-family: courier;">--enable-experimental-zts</span> for PHP4, <span style="font-family: courier;">--enable-maintainer-zts</span> for PHP5), and the name of the <span style="font-family: courier;">#define</span>'d preprocessor token used inside the engine to determine if the TSRM layer is being used.</dd><br /><br /><dt>tsrm_ls</dt> <dd>TSRM <b>l</b>ocal <b>s</b>torage - This is the actual variable name being passed around inside the TSRMLS_* macros when ZTS is enabled. It acts as a pointer to the start of that thread's independent data storage block which I'll cover in just a minute</dd><br /><br /><dt>TSRMLS_??</dt> <dd>A quartet of macros designed to make the differences between ZTS and non-ZTS mode as painless as possible. When ZTS is <i>not</i> enabled, all four of these macros evaluate to nothing. When ZTS is enabled however, they expand out to the following definitions: <ul style="font-family: courier new;"><li>TSRMLS_C tsrm_ls</li><li>TSRMLS_D void ***tsrm_ls</li><li>TSRMLS_CC , tsrm_ls</li><li>TSRMLS_DC , void ***tsrm_ls</li></ul></dd> <h3>Globals</h3> <p>In any normal C program (just like in PHP) you have two methods of getting data access to the same block of data in two different functions. One method is to pass the value on the parameter stuck like so:</p> <blockquote><pre><span style="font-family: courier new;font-size:78%;" >#include <stdio.h><br /><br />void output_func(char *message)<br />{<br /> printf("%s\n", message);<br />}<br /><br />int main(int argc, char *argv[])<br />{<br /> output_func(argv[0]);<br /><br /> return 0;<br />}</span><br /></pre></blockquote> <p>Alternately, you could store the value in a variable up in the global scope and let the function access it there:</p> <blockquote><pre><span style="font-family: courier new;font-size:78%;" >#include <stdio.h><br /><br />char *message;<br /><br />void output_func(void)<br />{<br /> printf("%s\n", message);<br />}<br /><br />int main(int argv, char *argv[])<br />{<br /> message = argv[0];<br /> output_func();<br /><br /> return 0;<br />}</span><br /></pre></blockquote> <p>Both approaches have their merits and drawbacks and typically you'll see some combination of the two used in a real application. Indeed, PHP is covered in global variables from resource type identifiers, to function callback pointers, to request specific information such as the symbol tables used to store userspace variables. Attempting to pass these values around in the parameter stack would be more than unruly, it'd be impossible for an application like PHP where it's often necessary to register callbacks with external libraries which don't support context data.</p><br /><p>So common information, like the execution stack, the function and class tables, and extension registries all sit up in the global scope where they can be picked up and used at any point in the application. For single-threaded SAPIs like CLI, Apache1, or even Apache2-prefork, this is perfectly fine. Request specific structures are initialized during the RINIT/Activation phase, and reset back to their original values during the RSHUTDOWN/Deactivation phase in preparation for the next request. A given webserver like Apache1 can serve up multiple pages at once because it spawns multiple processes each in their own process space with their own independant copies of global data.</p><br /><p>Now let's introduce threaded webservers like Apache2-worker, or IIS. Under these conditions, only one process space is active at a given time with multiple threads spun off. Each of these threads then act in the same manner as a single-threaded process might; Servicing requests one-at-a-time as dispatched by inbound requests. The trouble starts to brew as two or more threads try to service the a request at the same time. Each thread wants to use the global scope to store its request-specific information, and tries to do so by writing to the same storage space. At the least, this would result in userspace variables declared in one script showing up in another. In practice, it leads to quick and disasterous segfaults and completely unpredictable behavior as memory is double freed or written with conflicting information by separate threads.</p><br /><h3>Non-Global Globals</h3> <p>The solution is to require the engine, the core, and any extension using global storage to determine how much memory will be used by request-specific data. Then, at the spin-up of each new thread, allocate a chunk of memory for each of these players to store their data into thus giving each thread its own <i>local storage</i>. In order to group all the individual chuncks used by a given thread together, one last vector of pointers is allocated to store the individual sub-structure pointers into. It's the pointer to this vector which is passed around as the <span style="font-family: courier;">tsrm_ls</span> variable by the TSRMLS_* family of macros. To see how this works, let's look at a example extension:</p><br /><blockquote><pre><span style="font-family: courier new;font-size:78%;" >typedef struct _zend_myextension_globals {<br /> int foo;<br /> char *bar;<br />} zend_myextension_globals;<br /><br />#ifdef ZTS<br />int myextension_globals_id;<br />#else<br />zend_myextension_globals myextension_globals;<br />#endif<br /><br />/* Triggered at the beginning of a thread */<br />static void php_myextension_globals_ctor(zend_myextension_globals *myext_globals TSRMLS_DC)<br />{<br /> myext_globals->foo = 0;<br /> myext_globals->bar = NULL;<br />}<br /><br />/* Triggered at the end of a thread */<br />static void php_myextension_globals_dtor(zend_myextension_globals *myext_globals TSRMLS_DC)<br />{<br /> if (myext_globals->bar) {<br /> efree(myext_globals->bar);<br /> }<br />}<br /><br />PHP_MINIT_FUNCTION(myextension)<br />{<br />#ifdef ZTS<br /> ts_allocate_id(&amp;myextension_globals_id, sizeof(zend_myextension_globals),<br /> php_myextension_globals_ctor, php_myextension_globals_dtor);<br />#else<br /> php_myextension_globals_ctor(&amp;myextension_globals TSRMLS_CC);<br />#endif<br /><br /> return SUCCESS;<br />}<br /><br />PHP_MSHUTDOWN_FUNCTION(myextension)<br />{<br />#ifndef ZTS<br /> php_myextension_globals_dtor(&amp;myextension_globals TSRMLS_CC);<br />#endif<br /><br /> return SUCCESS;<br />}</span><br /></pre></blockquote> <p>Here you can see the extension declaring its global requirements to the TSRM layer by stating that it needs <span style="font-family: courier;">sizeof(zend_myextension_globals)</span> bytes of storage, and providing callbacks to use when initializing (or destroying) a given thread's local storage. The value populated into <span style="font-family: courier;">myextension_globals_id</span> represents the offset (common to all threads) into the <span style="font-family: courier;">tsrm_ls</span> vector where the pointer to that thread's local storage can be found. In the event that ZTS is not enabled, the data storage is simply placed into the true global scope and the thread initialization and shutdown routines are called manually during the Module's Startup and Shutdown phases. If you're wondering why <span style="font-family: courier;">TSRMLS_CC</span> was included in the non-ZTS blocks, then I clearly havn't made you fall asleep yet. Those aren't needed there since we know they evaluate to nothing, but it helps encourage good habits to include them anywhere the function's prototype calls for them.</p><br /><h3>Putting it all together</h3> <p>The final piece of this thread-safe puzzle comes from the question: "How do I access data in these structures?" And the answer to that question comes in the form of another familiar looking macro. Each extension or core component defines, in one of its header files, a macro which looks something like the following:</p><br /><blockquote><pre><span style="font-size:78%;"><span style="font-family: courier new;">#ifdef ZTS</span><br /><span style="font-family: courier new;"># define MYEXTENSION_G(v) \</span><br /><span style="font-family: courier new;"> (((zend_myextension_globals*)(*((void ***)tsrm_ls))[(myextension_globals_id)-1])->v)</span><br /><span style="font-family: courier new;">#else</span><br /><span style="font-family: courier new;"># define MYEXTENSION_G(v) (myextension_globals.v)</span><br /><span style="font-family: courier new;">#endif</span></span><br /></pre></blockquote> <p>Thus, when ZTS is not enabled, this macro simply plucks the right value out of the imediate value in the global scope, otherwise it uses the ID to locate the thread's local storage copy of the structure and derefence the value from there.</p><br /><p>Wanna know more, like how to deal with foreign callbacks where <span style="font-family: courier;">tsrm_ls</span> isn't available? <b>Buy my book!</b></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/14557640555210645219' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/14557640555210645219' rel='author' title='author profile'> <span itemprop='name'>Sara Golemon</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html' itemprop='url'/> <a class='timestamp-link' href='http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2006-06-01T13:08:00-07:00'>13:08</abbr></a> </span> <span class='post-comment-link'> <a class='comment-link' href='http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html#comment-form' onclick=''> 2 comments: </a> </span> <span class='post-icons'> <span class='item-control blog-admin pid-950715124'> <a href='https://www.blogger.com/post-edit.g?blogID=1234953837283832282&postID=2778191266369728679&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=2778191266369728679&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=2778191266369728679&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=2778191266369728679&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=2778191266369728679&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=1234953837283832282&postID=2778191266369728679&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='http://blog.golemon.com/search/label/favorite' rel='tag'>favorite</a>, <a href='http://blog.golemon.com/search/label/php' rel='tag'>php</a>, <a href='http://blog.golemon.com/search/label/tsrmls' rel='tag'>tsrmls</a>, <a href='http://blog.golemon.com/search/label/tsrmls_cc' rel='tag'>tsrmls_cc</a>, <a href='http://blog.golemon.com/search/label/zend' rel='tag'>zend</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='http://blog.golemon.com/search?updated-max=2007-09-15T10:41:00-07:00&max-results=7&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'>Newer Posts</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://blog.golemon.com/search?updated-max=2006-06-01T13:08:00-07:00&max-results=7' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='http://blog.golemon.com/'>Home</a> </div> <div class='clear'></div> <div class='blog-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='http://blog.golemon.com/feeds/posts/default' target='_blank' type='application/atom+xml'>Posts (Atom)</a> </div> </div> </div></div> </div> <div id='sidebar-wrapper'> <div class='sidebar section' id='sidebar'><div class='widget LinkList' data-version='1' id='LinkList1'> <h2>Favorites</h2> <div class='widget-content'> <ul> <li><a href='http://saragolemon.blogspot.com/2006/06/how-long-is-piece-of-string.html'>Pieces of string</a></li> <li><a href='http://saragolemon.blogspot.com/2007/01/youre-being-lied-to.html'>Lies & References</a></li> <li><a href='http://saragolemon.blogspot.com/2008/01/understanding-opcodes.html'>Opcodes</a></li> <li><a href='http://saragolemon.blogspot.com/2006/05/last-month-at-phptek-i-gave.html'>Compiled Variables</a></li> <li><a href='http://saragolemon.blogspot.com/2006/06/what-heck-is-tsrmlscc-anyway.html'>TSRMLS_CC</a></li> </ul> <div class='clear'></div> </div> </div><div class='widget LinkList' data-version='1' id='LinkList2'> <h2>Extension Writing</h2> <div class='widget-content'> <ul> <li><a href='http://blog.golemon.com/2015/01/hhvm-extension-writing-part-i.html'>HHVM Extensions I</a></li> <li><a href='http://blog.golemon.com/2015/01/hhvm-extension-writing-part-ii.html'>HHVM Extensions II</a></li> <li><a href='http://blog.golemon.com/2015/01/hhvm-extension-writing-part-iii.html'>HHVM Extensions III</a></li> <li><a href='http://blog.golemon.com/2015/01/hhvm-extension-writing-part-iv.html'>HHVM Extensions IV</a></li> <li><a href='http://devzone.zend.com/article/1021-Extension-Writing-Part-I-Introduction-to-PHP-and-Zend'>PHP Extensions I</a></li> <li><a href='http://devzone.zend.com/article/1022-Extension-Writing-Part-II-Parameters-Arrays-and-ZVALs'>PHP Extensions IIa</a></li> <li><a href='http://devzone.zend.com/article/1023-Extension-Writing-Part-II-Parameters-Arrays-and-ZVALs-continued'>PHP Extensions IIb</a></li> <li><a href='http://devzone.zend.com/article/1024-Extension-Writing-Part-III-Resources'>PHP Extensions III</a></li> </ul> <div class='clear'></div> </div> </div><div class='widget HTML' data-version='1' id='HTML1'> <h2 class='title'>External links</h2> <div class='widget-content'> <a href="https://github.com/sgolemon"><nobr>github/sgolemon</nobr></a><br/> <a rel="me" href="https://mastodon.technology/@saramg"><nobr>@saramg@mastodon.technology</nobr></a> </div> <div class='clear'></div> </div><div class='widget Subscribe' data-version='1' id='Subscribe1'> <div style='white-space:nowrap'> <h2 class='title'>Subscribe...</h2> <div class='widget-content'> <div class='subscribe-wrapper subscribe-type-POST'> <div class='subscribe expanded subscribe-type-POST' id='SW_READER_LIST_Subscribe1POST' style='display:none;'> <div class='top'> <span class='inner' onclick='return(_SW_toggleReaderList(event, "Subscribe1POST"));'> <img class='subscribe-dropdown-arrow' src='https://resources.blogblog.com/img/widgets/arrow_dropdown.gif'/> <img align='absmiddle' alt='' border='0' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> Posts </span> <div class='feed-reader-links'> <a class='feed-reader-link' href='https://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fblog.golemon.com%2Ffeeds%2Fposts%2Fdefault' target='_blank'> <img src='https://resources.blogblog.com/img/widgets/subscribe-netvibes.png'/> </a> <a class='feed-reader-link' href='https://add.my.yahoo.com/content?url=http%3A%2F%2Fblog.golemon.com%2Ffeeds%2Fposts%2Fdefault' target='_blank'> <img src='https://resources.blogblog.com/img/widgets/subscribe-yahoo.png'/> </a> <a class='feed-reader-link' href='http://blog.golemon.com/feeds/posts/default' target='_blank'> <img align='absmiddle' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> Atom </a> </div> </div> <div class='bottom'></div> </div> <div class='subscribe' id='SW_READER_LIST_CLOSED_Subscribe1POST' onclick='return(_SW_toggleReaderList(event, "Subscribe1POST"));'> <div class='top'> <span class='inner'> <img class='subscribe-dropdown-arrow' src='https://resources.blogblog.com/img/widgets/arrow_dropdown.gif'/> <span onclick='return(_SW_toggleReaderList(event, "Subscribe1POST"));'> <img align='absmiddle' alt='' border='0' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> Posts </span> </span> </div> <div class='bottom'></div> </div> </div> <div class='subscribe-wrapper subscribe-type-COMMENT'> <div class='subscribe expanded subscribe-type-COMMENT' id='SW_READER_LIST_Subscribe1COMMENT' style='display:none;'> <div class='top'> <span class='inner' onclick='return(_SW_toggleReaderList(event, "Subscribe1COMMENT"));'> <img class='subscribe-dropdown-arrow' src='https://resources.blogblog.com/img/widgets/arrow_dropdown.gif'/> <img align='absmiddle' alt='' border='0' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> All Comments </span> <div class='feed-reader-links'> <a class='feed-reader-link' href='https://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fblog.golemon.com%2Ffeeds%2Fcomments%2Fdefault' target='_blank'> <img src='https://resources.blogblog.com/img/widgets/subscribe-netvibes.png'/> </a> <a class='feed-reader-link' href='https://add.my.yahoo.com/content?url=http%3A%2F%2Fblog.golemon.com%2Ffeeds%2Fcomments%2Fdefault' target='_blank'> <img src='https://resources.blogblog.com/img/widgets/subscribe-yahoo.png'/> </a> <a class='feed-reader-link' href='http://blog.golemon.com/feeds/comments/default' target='_blank'> <img align='absmiddle' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> Atom </a> </div> </div> <div class='bottom'></div> </div> <div class='subscribe' id='SW_READER_LIST_CLOSED_Subscribe1COMMENT' onclick='return(_SW_toggleReaderList(event, "Subscribe1COMMENT"));'> <div class='top'> <span class='inner'> <img class='subscribe-dropdown-arrow' src='https://resources.blogblog.com/img/widgets/arrow_dropdown.gif'/> <span onclick='return(_SW_toggleReaderList(event, "Subscribe1COMMENT"));'> <img align='absmiddle' alt='' border='0' class='feed-icon' src='https://resources.blogblog.com/img/icon_feed12.png'/> All Comments </span> </span> </div> <div class='bottom'></div> </div> </div> <div style='clear:both'></div> </div> </div> <div class='clear'></div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(4)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2015/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2009/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2009/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(5)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2008/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2008/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2007/'> 2007 </a> <span class='post-count' dir='ltr'>(5)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2007/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2007/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2007/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2007/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/'> 2006 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='posts'> <li><a href='http://blog.golemon.com/2006/06/how-long-is-piece-of-string.html'>How long is a piece of string</a></li> <li><a href='http://blog.golemon.com/2006/06/extending-and-embedding-php.html'>Extending and Embedding PHP</a></li> <li><a href='http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html'>What the heck is TSRMLS_CC, anyway?</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/04/'> April </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='http://blog.golemon.com/2006/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div><div class='widget Profile' data-version='1' id='Profile1'> <h2>About Me</h2> <div class='widget-content'> <a href='https://www.blogger.com/profile/14557640555210645219'><img alt='My photo' class='profile-img' height='80' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_WelyvrVLA3QIiS5atrXIN36SwgESeRo8979FPSxJPsaZP30AkVCIfj-g5hdTmZ10fZ3eDQxfIW8ao-7CEU0HFdUgMyzlophziSOOzlJwJwckA3UOyXcta6_rFeI_TQ/s220/saramg.jpg' width='80'/></a> <dl class='profile-datablock'> <dt class='profile-data'> <a class='profile-name-link g-profile' href='https://www.blogger.com/profile/14557640555210645219' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'> Sara Golemon </a> </dt> </dl> <a class='profile-link' href='https://www.blogger.com/profile/14557640555210645219' rel='author'>View my complete profile</a> <div class='clear'></div> </div> </div></div> </div> <!-- spacer for skins that want sidebar and main to be the same height--> <div class='clear'>&#160;</div> </div> <!-- end content-wrapper --> <div id='footer-wrapper'> <div class='footer no-items section' id='footer'></div> </div> </div></div> <!-- end outer-wrapper --> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/2725212210-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY4BWc_vFUiMfr4TNjhBNZVe9ylkkw:1740575656719';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d1234953837283832282','//blog.golemon.com/2006/06/','1234953837283832282'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '1234953837283832282', 'title': 'Still trying to get it all out', 'url': 'http://blog.golemon.com/2006/06/', 'canonicalUrl': 'http://blog.golemon.com/2006/06/', 'homepageUrl': 'http://blog.golemon.com/', 'searchUrl': 'http://blog.golemon.com/search', 'canonicalHomepageUrl': 'http://blog.golemon.com/', 'blogspotFaviconUrl': 'http://blog.golemon.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': false, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': '', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Still trying to get it all out - Atom\x22 href\x3d\x22http://blog.golemon.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Still trying to get it all out - RSS\x22 href\x3d\x22http://blog.golemon.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Still trying to get it all out - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/1234953837283832282/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/f04e4d11442969dd', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': 'June 2006', 'pageTitle': 'Still trying to get it all out: June 2006'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'isResponsive': false, 'isAlternateRendering': false, 'isCustom': false}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Still trying to get it all out', 'description': '', 'url': 'http://blog.golemon.com/2006/06/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2006, 'month': 6, 'rangeMessage': 'Showing posts from June, 2006'}}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/177302283-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LinkListView', new _WidgetInfo('LinkList1', 'sidebar', document.getElementById('LinkList1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LinkListView', new _WidgetInfo('LinkList2', 'sidebar', document.getElementById('LinkList2'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML1', 'sidebar', document.getElementById('HTML1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_SubscribeView', new _WidgetInfo('Subscribe1', 'sidebar', document.getElementById('Subscribe1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'sidebar', document.getElementById('Profile1'), {}, 'displayModeFull')); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10