Successfully reported this slideshow.
Your SlideShare is downloading. ×

Php extensions

Ad

PHP EXTENSIONS
Making the language even better

Ad

Congratulations!
• You’ve decided to learn “down the stack”
• You’ll learn more than you do “across the stack”
• Your brai...

Ad

WARNING!
The things shown here to apply to PHP 5.4 – PHP 5.x

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Upcoming SlideShare
Php Extensions for Dummies
Php Extensions for Dummies
Loading in …3
×

Check these out next

1 of 81 Ad
1 of 81 Ad
Advertisement

More Related Content

Advertisement
Advertisement

Php extensions

  1. 1. PHP EXTENSIONS Making the language even better
  2. 2. Congratulations! • You’ve decided to learn “down the stack” • You’ll learn more than you do “across the stack” • Your brain will hurt a bit • This will require you to be involved in your own learning process • It is HARD WORK to be good at anything new
  3. 3. WARNING! The things shown here to apply to PHP 5.4 – PHP 5.x
  4. 4. Why do extensions? • Talk to a C or C++ library • Modify the way the engine works (zend extensions usually) • Make slow parts of code run faster
  5. 5. But I want to change the engine! Baby steps, baby steps
  6. 6. Wrapper Extension Speed and/or Algorithm Extension Zend Extension SAPI Engine - Lexer, AST, Parser
  7. 7. But I don’t know C! 1. compiled 2. strictly typed 3. php internals do “hard” stuff 4. copy and paste! boilerplate and macros 5. cairo, pecl_http, date 6. Don’t do the hard stuff first! lxr.php.net
  8. 8. But I want to learn C
  9. 9. Also try: • http://www.learn-c.org/ • http://c.learncodethehardway.org/book/ • http://aelinik.free.fr/c/ Practice Practice Practice!
  10. 10. Preparing to Compile The big list
  11. 11. Quick Setup Needs 1. compiler 2. sdk 3. tools 4. dependencies 5. code phpize is your friend!
  12. 12. How to Compile an Extension 1. phpize 2. ./configure 3. make 4. make install 5. make test configure might require –with-php-config=/path/to/something but…
  13. 13. But wait – there’s more! • Compile your own PHP source, use a –prefix  /usr/local/php-5.6-debug-zts is one I use  I also have 20 php’s installed  • We want developer specific flags  --enable-maintainer-zts and --enable-debug  optionally –enable-gcov • install gdb and valgrind and optionally lcov • this is easy on Ubuntu and similar systems where packages are easy to get • You can also compile php with clang instead of gcc and do things like use static analysis
  14. 14. Rasmus to the Rescue! • https://github.com/rlerdorf/php7dev/blob/master/README.md tl;dr 1. install virtualbox 2. install vagrant 3. git clone https://github.com/rlerdorf/php7dev.git 4. cd php7dev 5. vagrant up 6. vagrant ssh 7. sudo newphp 56 debug zts
  15. 15. How to Play along git clone https://github.com/auroraeosrose/php-extensions- code.git git clone git://github.com/auroraeosrose/php- extensions-code.git git checkout scaffolding bookmark lxr.php.net – you will be using it a lot phpize ./configure make make test
  16. 16. Let’s write an extension! But wait – there’s more….
  17. 17. 1. Set up compile environment 2. Write a module definition 3. Learn about the PHP lifecycle 4. Learn about zvals 5. Add functions 6. ??? 7. Profit! Every Other Extensions Talk
  18. 18. DOIN IT RONG
  19. 19. Which do YOU want?
  20. 20. 1. Do something you can’t do in userland 2. Utilize a C library 3. Make slow code faster Maybe you should just use ffi! Step 1. Why?
  21. 21. What is FFI? • Foreign function interface • Java calls it JNI • HHVM calls it HNI • Python calls it “ctypes” (do not ask, stupidest name ever) • C# calls it P/Invoke • Ruby calls it FFI • PHP calls it…
  22. 22. FFI
  23. 23. Oh wait… • php’s ffi is rather broken (last release is 2004-01-20) • php’s ffi has no maintainer (ilia and wez were doing it) • It needs some TLC • Are you interested and not afraid? See me!
  24. 24. 1. I hate parsing URIs 2. PHP’s parse_url is… not the best 3. How about an extension that wraps something that parses uris in an excellent fashion 4. RESEARCH TIME Step 2. What
  25. 25. Google says…
  26. 26. C library to the rescue! • uriparser.sourceforge.net • strictly RFC 3986 compliant • available on many systems as packages • cross platform • documented http://uriparser.sourceforge.net/doc/html/
  27. 27. 1. Think about what the API should be 2. Look at the C APIs but don’t mimic them 3. Write an example of how you WANT it to work 4. Write more then one example! 5. Turn these examples into your first tests 6. Yes this is TDD Step 3. How
  28. 28. 1. This is copy and paste 1. config.m4 & config.w32 2. macros for version api changes if necessary 3. main module file (php_{$ext}.c) 4. main header file (php_{$ext}.h) 2. Compile it and test! Step 6. Extension Scaffolding
  29. 29. Configure files
  30. 30. Module struct
  31. 31. Scaffolding rules 1. make sure you name your files in a standard way 2. document! use a license header, proto statements 3. read the coding standards http://lxr.php.net/xref/PHP_5_6/CODING_STANDA RDS 4. FOLLOW THE CODING STANDARDS 5. use version control early on – github is easy!
  32. 32. php –d extension=myext.so –m The scaffold extension should show up in the list Make sure to 1. define a version constant 2. read and use PHP code standards Check if it works
  33. 33. 1. run-test.php 2. make test will magically have output more at http://qa.php.net/write-test.php and docs at http://qa.php.net/phpt_details.php Step 7. Write the test
  34. 34. PHPT tests
  35. 35. Let’s take a break here for some semi-live demos…
  36. 36. Zval The guts behind PHP’s type system
  37. 37. Typing systems compared Static Typing (C) • Variables must be declared before use • Variables must be given a type at declaration • “compile time” checking Dynamic Typing (PHP) • Variables don’t have to be declared before use • Variables can change types • “run time” checking
  38. 38. zval
  39. 39. long any numeric double numeric with decimal char* + int (length) strings, binary Hashtable dictionaries, arrays,structs object any complicated type
  40. 40. How do I get C types from a ZVAL? Z_LVAL(zval) Z_LVAL_P(zval_p) Z_LVAL_PP(zval_pp) Z_BVAL(zval) Z_BVAL_P(zval_p) Z_BVAL_PP(zval_pp) Z_DVAL(zval) Z_DVAL_P(zval_p) Z_DVAL_PP(zval_pp) Z_STRVAL(zval) Z_STRVAL_P(zval_p) Z_STRVAL_PP(zval_pp) Z_STRLEN(zval) Z_STRLEN_P(zval_p) Z_STRLEN_PP(zval_pp) Z_ARRVAL(zval) Z_ARRVAL_P(zval_p) Z_ARRVAL_PP(zval_pp) Z_OBJVAL(zval) Z_OBJVAL_P(zval_p) Z_OBJVAL_PP(zval_pp) Z_OBJ_HANDLE(zv al) Z_OBJ_HANDLE_P(zval _p) Z_OBJ_HANDLE_PP(zval_ pp) Z_OBJ_HT(zval) Z_OBJ_HT_P(zval_p) Z_OBJ_HT_PP(zval_pp) Z_OBJCE(zval) Z_OBJCE_P(zval_p) Z_OBJCE_PP(zval_pp) Z_OBJPROP(zval) Z_OBJPROP_P(zval_p) Z_OBJPROP_PP(zval_pp) Z_TYPE(zval) Z_TYPE_P(zval_p) Z_TYPE_PP(zval_pp)
  41. 41. My extension does nothing! Back to our regularly schedule content
  42. 42. 1. tell it to link to our C library 2. add a function 3. learn how to get data 4. learn how to return data Step 8. Actually do something
  43. 43. I hate autotools… • Also known as the gnu build system • provider of much pain, but much good use as well • autoconf – generates a configure script (we cheat with phpize on shared extensions)  makes a configure we run to set up our information, mainly a config.h file • automake – creates makefiles • libtool – creates static and dynamic libraries • Windows? Well php wrote it’s own version of autotools – in jscript (windows javascript variant)
  44. 44. Anatomy of a Function
  45. 45. Wait – what was that? • Define your function in C  use a special call to parse parameters passed by the user  use a special zval to return data to the user • Tell PHP your extension provides this function  put it in your “giant struct of doom” that lists them all  send it to php when in your module struct • Tell PHP what arguments your extension provides  If your argument information and zpp argue users will be angry  Yes it sucks you can’t just do one 
  46. 46. php type code c type array or object a zval * boolean b zend_bool class C zend_class_entry * double d double callable f zend_fcall_info andzend_fcall_info_cache array or HASH_OF(object) H HashTable* array h HashTable* integer l long (NOT INT) integer L long with LONG_MAX, LONG_MIN limits object o zval * object of specific type O zval *, zend_class_entry string (no null bytes) p char*, int resource r zval * string (possible null bytes) s char*, int actual zval z zval * actual zval Z zval**
  47. 47. zend_parse_parameters type code variable args (any) * int, zval*** variable args (1 or more) + int, zval*** | anything after is optional, use defaults / use SEPARATE_ZVAL_IF_NOT_REF doesn’t apply to b, l, and d ! C NULL for zval null
  48. 48. return_value RETURN_RESOURCE(l) RETURN_BOOL(b) RETURN_NULL() RETURN_LONG(l) RETURN_DOUBLE(d) RETURN_STRING(s, duplicate) RETURN_STRINGL(s, l, duplicate) RETURN_EMPTY_STRING() RETURN_ZVAL(zv, copy, dtor) RETURN_FALSE RETURN_TRUE RETVAL_RESOURCE(l) RETVAL_BOOL(b) RETVAL_NULL() RETVAL_LONG(l) RETVAL_DOUBLE(d) RETVAL_STRING(s, duplicate) RETVAL_STRINGL(s, l, duplicate) RETVAL_EMPTY_STRING() RETVAL_ZVAL(zv, copy, dtor) RETVAL_FALSE RETVAL_TRUE
  49. 49. Complex Data array_init() add_(index|assoc)_long() add_(index|assoc)_bool() add_(index|assoc)_string() object_init() add_property_long() add_property_bool() add_property_string()
  50. 50. Now to visit the attach-library branch…
  51. 51. 1. namespaces 2. classes 3. methods 4. constants Step 9. Make it shiny
  52. 52. Classes 1. name, parent, and flags 2. hashtables of methods, default methods, static methods 3. hashtables of static properties, default properties, and properties 4. object handlers 5. union of either file information, or internal structures (for internal classes)
  53. 53. add-basic-class branch
  54. 54. Lifecycle Let’s take a moment to learn about how PHP works internally
  55. 55. Lifecycle PHP stops MSHUTDOWN – for each extension RSHUTDOWN – for each request cleanup after test.php RINIT – for each request execute test.php MINIT – for each extension request/parse test.php PHP starts php test.php
  56. 56. Lifecycle Threaded PHP stops MSHUTDOWN – for each extension request index.php request foo.php RINIT – for each request • execute test.php RSHUTDOWN – for each request • cleanup after test.php RINIT – for each request • execute test.php RSHUTDOWN – for each request • cleanup after test.php MINIT – for each extension apache starts
  57. 57. Class Properties
  58. 58. add-class-properties branch
  59. 59. Class Constants
  60. 60. add-class-constants branch
  61. 61. My class does nothing! Methods are where it’s at
  62. 62. Class Methods
  63. 63. add-class-methods branch
  64. 64. Alter $this
  65. 65. manipulate this branch
  66. 66. Abstract, Interface, Trait Class Method ZEND_ACC_IMPLICIT_ABSTRACT_CLA SS ZEND_ACC_STATIC ZEND_ACC_EXPLICIT_ABSTRACT_CLA SS ZEND_ACC_ABSTRACT ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL ZEND_ACC_INTERFACE ZEND_ACC_PUBLIC ZEND_ACC_TRAIT ZEND_ACC_PROTECTED ZEND_ACC_PRIVATE ZEND_ACC_CTOR ZEND_ACC_DTOR ZEND_ACC_CLONE spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; PHP_ME(DateTime, __construct, arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
  67. 67. 1. globals 2. memory management 3. custom objects 4. object handlers 5. thread safety Step 10: Advanced topics
  68. 68. 1. in your header – use ZEND_BEGIN|END_MODULE_GLOBALS 2. create the global access macro in your header (copy and paste) 3. ZEND_DECLARE_MODULE_GLOBALS in every file where you will use them 4. use the macro to access COUNTER_G(basic_counter_value)); } 5. Create ginit/gshutdown functions if your globals need initializing , etc Global Variables (threads = evil)
  69. 69. emalloc( ) • allocates the specified number of bytes safe_emalloc() • like emalloc but adds a special protection against overflows efree( ) • releases the specified block of memory back to the system estrdup( ) • allocate a buffer and copy the string into that buffer estrndup( ) • same as estrdup when you already know the length of the string ecalloc( ) • allocates the number of bytes and initializes them to zero erealloc( ) • resizes the specified block of memory https://wiki.php.net/internals/zend_mm
  70. 70. 1. clean up what you emalloc (C level destructor) 2. read wiki on how to make them extendable!
  71. 71. Object Handlers (black magic) https://wiki.php.net/internals/engine/objects
  72. 72. TSRM thread safe resource manager ZTS zend thread safety • tsrm_lsTSRMLS_C • void ***tsrm_lsTSRMLS_D • , tsrm_lsTSRMLS_CC • , void ***tsrm_lsTSRMLS_DC
  73. 73. 1. http://edit.php.net 2. http://svn.php.net/viewvc/phpdoc/en/trunk/reference/ 3. PhD is awesomesauce • http://doc.php.net/phd/ 4. email pecl-dev@lists.php.net 1. who you are 2. what you wrote (with links to your code!) 3. why you think it should be in pecl 5. poke me (or other devs) Document, PECL, release
  74. 74. Stuff I didn’t talk about 1. resources (use custom objects instead) 2. ini entries (just DON’T) 3. threading and parallel processing 4. engine hooking 5. streams and transports
  75. 75. PHP 7 is coming! gophp7-ext and php extension ecosystems
  76. 76. About Me  http://emsmith.net  auroraeosrose@gmail.com  twitter - @auroraeosrose  IRC – freenode – auroraeosrose  #phpmentoring  #gophp7-ext
  77. 77. Questions? HELP WITH DOCS! http://edit.php.net http://wiki.php.net/internals HELP WITH THE FUTURE http://gophp7.org/gophp7-ext

Editor's Notes

  • I mentor PHP developers into becoming C developers – because other PHP devs have done that for me

    If you want to move on and do more with extensions after this talk please talk to me – I also sit on freenode all day and answer questions and give feedback – always always want more code monkeys and fresh blood in any project

    and looking at extensions makes me sad – 99% suck
  • Give my short talk about why learning “down the stack” is so important and why more
    developers need to stop asking should I learn python or perl

    it’s better to learn in a domain entirely different than what you are currently doing

    if you do desktop learn web, if you learn web do desktop or mobile
    if you do PHP, don’t learn “across” (perl, python, ruby) learn DOWN
    java, C#, go, rust
    obj-c, C, c++
    assembler

    the old gurus of C who built what we play with are dying off (do the math, how old is rasmus?)

    there won’t be hand holding, but a good mentor (for now me) will help you learn what you need to know
  • PHP 7 will be breaking all the rules here, changing things in a fundamental manner, just something to keep in mind
    We’re working on a project to make migrating to PHP7 well documented and easy when the time comes
    and also working on ways to improve extensions in general
  • This is the reason we have PHP extensions
    to hit the lower level parts of the code that are so important

    But the top reason is the #1 reason we write PHP extensions
  • This is usually the first thing people think of when they want to “get involved with PHP internals”
    But you will have a far easier time of things if you start with extensions
  • This is the proper path to get involved in PHP and the language - learning each piece of the stack step by step will
    make you not only a better program, and understand the language
    but it will make you a better part of the community
  • This is the #1 argument I hear – but really is not anything you need to worry about

    c98 people! you can use some c99 stuff but declarations MUST go at the top of blocks (that’s really good coding standards anyway)
    although this will be moot when Microsoft finally gets it’s CTP for 2015

    just like php itself turn all your errors on when compiling (-wall is your friend) and try to code clean

    you don’t have to “know C” anymore then you have to “know PHP” to write a wordpress plugin
    if you have the very basics of what to do it’s not hard
    PHP takes care of a lot of the heavy lifting – from how to parse parameters coming in and how to shove data into someplace going out…
    to how to do fancy objects

    Unless you’re doing something REALLY evil (an opcode cache, changing the way the engine works, threading) most of this stuff has already been done for another extension, it’s just a matter of finding the code – compile and test

    btw, all the code generators out there currently suck – most don’t do test generation, doc generation, or use the proper apis
  • This is the book you want
    it’s affectionately called the C bible
    if you walk through this book and do the exercise you’ll get the basics of C
  • These are some pretty good free resources for learning C – walking through the two books and the online tutorial will get you a good portion of the way there

    remember programming is thinking as much as writing code
    as if you play piano or dance you must practice practice practice
  • So you’ll need to actually have an environment set up to compile PHP on
    I will say right now for your first foray into extensions you will be happiest on linux
    a VM is fine, in a debian/ubuntuish flavor because you’ll get a lot more help and support

    Also programming for windows and OSX is something you’ll need to learn before you finalize that extension but are much
    harder (yes, even OSX is harder – to do it right on there you use homebrew or something similar to install a linux stack –
    would be easier at first just to set up a linux vm)
  • This is the same and yet different on every system and we’re not going to go into it a whole lot – this should have been homework before you came ;)

    Basically you need a compiler – xcode on mac, vc(2008) express on windows, gcc something on linux – this is different for every system
    You also need the sdk and headers for your system – those will be put on with xcode, you’ll need the 6.1 windows sdk for windows

    Then you need autotools – bison, and re2c to build PHP

    On mac or linux you can use phpize to build extensions – You CAN do this on windows as well except that for some stupid reason the proper files are not shipped with windows binary builds (stupid)

    Then you need any depedencies (to build PHP as a base you need iconv, zlib, and libxml2 at a bare minimum)

    After you build PHP on windows you can use phpize (it will be generated for you) and makes life so much easier
  • make a note that windows does not need the ./ before configure and uses nmake instead of make (otherwise identical)
    Note that to use a specific PHP install use /full/path/to/phpize and –with-php-config=/usr/local/php5/bin/php-config

    Note this does shared extensions only – then again most of the extensions you’ll work on should probably be shared
  • So although I wont’ whine about it today – if you really want to do extensions properly you need to have your own php compile
    you need to not be afraid of gcc and clang
    you need to make sure you test and test and test
  • There, now we’ve switched to using a precompiled debug zts version of php 5.6
    WOOHOO

    There aren’t (yet) other box versions/providers available – this is ongoing work (more on gophp7-ext later)
  • I’m putting parts of this code onto my github account – each section I talk about – scaffolding, adding a function, ext, will have a different branch – feel free to clone and play

    These aren’t necessarily complicated extensions but they do follow PHP CS, have all the copy and paste you need and do compile (I think)
  • So the part we’re all excited about – let’s write an extension! I’ll just get some code and then you copy and compile it and then…
  • If you’ve ever seen another PHP extensions talk they dive into how to use the zend engine and how things work and such

    PHP is to C as wordpress is to PHP – makes any idiot able to write a plugin for it ;)

    you don’t necessarily HAVE to know how the internals work – you just have to know the right calls to make!

    So although I might tell you about SOME of the internals how and why, for the most part this will be “how to do it” not “why you do it”

    Because PHP is a ball of rusty nails ;)
  • In addition this is the absolutely wrong way to approach writing PHP extensions!

    Actually it’s the wrong way to approach writing LOTS of things

    do you start out writing a website worrying about how to make a db connection before you’ve designed the database and created the schema? do you create the schema before you have wireframes? just because we’re making a product in a different language doesn’t mean the rules change
  • this is why you really need to think about what you’re doing – being able to use the extension is not really enough… just wrapping a C api is a good way to give yourselves headaches of a horrible nature
    Please be the solution, not the problem
    We need no more painful APIs in PHP
  • so these are the reasons you’d write a PHP extension as we talked about before – you want to use a C library, you want to make something process intensive faster, you want to hook into the engine itself

    there aren’t other reasons to do an extension

    wait? what is FFI?


  • So many languages support this idea of calling into usually C code
    Then they usually put a layer of regular code “on top” to make APIS non painful
    This can be useful
    it also tends to be slower
  • before you get into extension writing – if you just want an ffi wrapper and are just going to call the exact C calls from an existing library why go to the trouble of writing an extension?

    ffi is pretty great but a bit of a flakey extension yet, but it’s identical to python’s “ctypes” which is a stupid name, it’s really ffi

    I hear al lthe time about how “great” python is because of ctypes, frankly I beg to differ. Part of wrappign a C extension is translating the C calls into something far more “phpish”
  • oh ffi is cool and so needs a maintainer
  • so this is what we want to do – write an extension that wraps a good C uri parsing library
  • so you need to do your research right? there are multiple C parsing libraries, joyent has one and there are some nice c++ ones, but for simple
    well laid out C uriparser seems to win – also it’s really nice

    use your internet tools – when you started PHP I’m sure you had books and stuff on speed dial
    you will need to do the same for C
  • SO this is a VERY nice C library for parsing uris according to the spec – USEFUL AS ALL GETOUT
    cross platform, well maintained, easy to use – don’t let the sourceforge URL fool you, it’s in git 
  • C++ APIs or similar wrappers in python, perl, ruby, etc are a better place to look for api ideas – try a couple of ways of using the apis as well

    really think about what kinds of apis and code you’re looking for – so I was looking at wrapping a small library (uriparser.sourceforge.net) and one of the things I did first was sit down and write some rough almost pseudo-code of what the extension might look like
  • uriparser.sourceforge.net – a simple uri parser library that strictly conforms to rfc

    questions to ask yourself as you write these examples
    do I want namespaces?
    will this be an object oriented api or a procedural style api?
    do I want to do the extra work of a dual api? (such as date or mysqli?)
    these decisions are usually pretty easy to figure out once you actually try to write the kind of code you want to work
  • PHP is 90% copy and paste, the main copy and paste stuff is all scaffolding for an extension

    so we’ve figure out what we want to write and how we want to write it, now we need to have scaffolding in place for it

    talk about our 4 files, the scaffold example - show the files quickly to show what normally goes in a header, some PHP CS rules, et al
  • DO BOTH unless you’re absolutely certain that whatever you’re writing will only work on one system or the other
    m4 is autotools stuff, but the w32 are very easy to write as well, they’re just jscript (windows javascript dialect) with some special functions
    for things like checking headers and adding libs, etc

    talk about with vs. enable
  • this is the very basic items you can have in your struct to define what you module is and what it does

    STANDARD_MODULE_HEADER_EX allows you to add ini entries and depedencies to your module definition

    using STANDARD_MODULE_PROPERTIES_EX allows you to add globals
    what the globals are, a ginit and a gshutdown – plus a “post deactivate” method that basically never gets used ;)
  • Just some general rules for you to take a look at

    even if your extension is not going into PHP proper the more time you take to properly document your code the happier you will be
  • how to see if what you’ve been playing with will actually work

    This should load your boring extension without doing anything fancy, just allow it to show up in the modules list

    you can actually do a test case for this with extension_loaded or get_loaded_modules if you’re so inclined
  • everybody should ALWAYS test their extensions – test test test
    turn debugging on, turn memory leaks on - run your tests

    if they fail you’ll get a bunch of extra files from the tests system available that make things very easy to debug, a diff file, .out file, even an .sh
    file to run the test exactly like it was run the first time

    no .bat file yet… yes I have a patch for that
  • These are very basic functional style tests

    there are a bunch of different sections for each one – the important thing to remember is

    always include a skipif
    anything in “tests” will be run so it’s ok to put things in directories for order
    write tests for everything you can think of! this is my standard test to check my phpinfo (MINFO) function
  • Look at the code and look at the compile
  • NOTE: again there were many underlying changes made to php’s zvals for php 7
    I’m not going to go into all the changes but I may mention a few

    we’re going to detour just a moment to learn something about PHP’s guts
  • But wait – PHP is sitting on C
    we are somehow translating C types to PHP types – how is this magic accomplished?
  • Our zval is a giant struct of doom

    for those of you who don’t know what a union is,

    A union, is a collection of variables of different types, just like a structure. However, with unions, you can only store information in one field at any one time. You can picture a union as like a chunk of memory that is used to store variables of different types. Once a new value is assigned to a field, the existing data is wiped over with the new data.

    This is what everything you do in C goes into!
  • So basically with an extension (especially one wrapping a library) what you’re doing
    is taking C variables and exposing them to php land by turning them into zvals

    So start by thinking about what PHP offers as variable types

    long lval; /* long value */
    309 double dval; /* double value */
    310 struct {
    311 char *val;
    312 int len;
    313 } str;
    314 HashTable *ht; /* hash table value */
    zend_object_value obj;


    so a “zval” in PHP has a union that can have the value of what is inside – something you’ll need to do when you create your extension is figure out how to “translate” that to a PHP type and how to handle it
  • p is for pointer (that’s good enough for me)

    these are helper macros to get the data OUT of that union of doom that you need, it’s also how you get zval types and other fun stuff

    note there are even MORE then this, but these are the ones you’ll use most often

    PHP is governed by macros and more macros, which is why it’s important to look at existing PHP extensions since 95% of the macros are NOT documented
  • Now let’s make our extension like… actually do something
  • So we’re going to actually write a function for our uriparser library that does something extremely simple – we’re going to register a function to tell us the uriparser library version
  • Here show all the lines required to do one thing – link into the library

    mention how other options are thin on the ground, although cmake is gainin some major traction
    about 2008 there was an attempt to port php’s build system to cmake

    sadly cmake was not really ready for it
    it IS ready for it now (hhvm and others all use cmake)
    But again that’s a monstrous project and you’re fighting a battle
    gains? one build system for everything ,not maintaining our own configure system for windows, easier integration into ecosystems

  • you need to do three things to add a function to your extension

    define it’s arguments – this is for reflection
    define it’s body
    put it inside a function struct

    arginfo must have the begin and end arginfo
    then you add additional arguments as desired in between
    if you have optional arguments, use begin_arginfo_ex

    you can send by val or reference or do typehinting with arginfo as well
  • SO a lot of this is implementation detail issues

    so in PHP you use this macro – all it does is rename your function name to something that won’t collide evilly, and define a bunch
    of C parameters you’re getting passed in 
  • there are even more than this
    in php7 strings move to use the more correct

    discuss longs v.s longs and 64 bit nonsense 
  • so you can also do “zend_parse_parameters_ex” the only thing you can do it with is QUIET

    there are a couple of reasons for doing this – mostly nesting and overloaded calls
  • This is macro hell – PHP is macro hell

    every PHP function (or method) has a return value available to you – an automatically NULL zval that you need ot manipulate in order to give information back

    it’s called return_value

    you manipulate these return value zvals to get data back into PHP userland

    the one thing that is
  • When you start to want to return complex data things get a little more complicated – this is where array and object init come in

    there are also ways to array_init with a specific length or object_init_ex which allows you to choose the type of object you’re creating

    there are a bunch more of these

    zend_API.h is your lifeblood for how to use these things, along with
  • Look at the code and look at the compile
    make clean, switch branch,

    sudo apt-get install liburiparser-dev -> that’ll get the latest into your vm if you have rasmus’s box up
  • Now we move on to more complex parts of the code, methods that really DO something

    remember we should start by writing tests for it
  • the struct for a zend_class_entry is SOOOO big I can’t show it on one slide ;)
    however it’s almost entirely pointers to other stuff

    struct _zend_class_entry {
    463 char type;
    464 const char *name;
    465 zend_uint name_length;
    466 struct _zend_class_entry *parent;
    467 int refcount;
    468 zend_uint ce_flags;
    469
    470 HashTable function_table;
    471 HashTable properties_info;
    472 zval **default_properties_table;
    473 zval **default_static_members_table;
    474 zval **static_members_table;
    475 HashTable constants_table;
    476 int default_properties_count;
    477 int default_static_members_count;
    478
    479 union _zend_function *constructor;
    480 union _zend_function *destructor;
    481 union _zend_function *clone;
    482 union _zend_function *__get;
    483 union _zend_function *__set;
    484 union _zend_function *__unset;
    485 union _zend_function *__isset;
    486 union _zend_function *__call;
    487 union _zend_function *__callstatic;
    488 union _zend_function *__tostring;
    489 union _zend_function *serialize_func;
    490 union _zend_function *unserialize_func;
    491
    492 zend_class_iterator_funcs iterator_funcs;
    493
    494 /* handlers */
    495 zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
    496 zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
    497 int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
    498 union _zend_function *(*get_static_method)(zend_class_entry *ce, char* method, int method_len TSRMLS_DC);
    499
    500 /* serializer callbacks */
    501 int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
    502 int (*unserialize)(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
    503
    504 zend_class_entry **interfaces;
    505 zend_uint num_interfaces;
    506
    507 zend_class_entry **traits;
    508 zend_uint num_traits;
    509 zend_trait_alias **trait_aliases;
    510 zend_trait_precedence **trait_precedences;
    511
    512 union {
    513 struct {
    514 const char *filename;
    515 zend_uint line_start;
    516 zend_uint line_end;
    517 const char *doc_comment;
    518 zend_uint doc_comment_len;
    519 } user;
    520 struct {
    521 const struct _zend_function_entry *builtin_functions;
    522 struct _zend_module_entry *module;
    523 } internal;
    524 } info;
    525};
  • TO do a class –

    create and register it’s CE in minit
    put it in another file – will keep yourself sane instead of having 300 mile long files
    some people whine that this makes it harder to use static stuff, since each file is compiled into it’s own “unit” and then linked
    but modern compilers and linkers make the overhead on this moot – better to be organized!
  • so this is how you would do your minit function – this would go into php_uriparser.c
    where the other code displayed would be in uri.c – where all our code for our uri class is going
    it is generally a good idea to keep arginfo and methods to gether as well in the code, so when one changes you remember to change the other

    remember stuff must be declared in order to be used too!

    the namespace declaration and the PHP_MINIT declaration go into the header file

    I often do a private header file for things like that – or do an api file if I allow things in my extension to be used by say other extensions
  • So this has ONLY the basics – explain how the minit works
    then let’s talk lifecycle
  • Deep breath – let’s talk about those things we put in the module struct
    Each are run at a different point in time

    let’s also talk a wee bit about structure? sapis?
  • so this is the lifecycle of PHP

    each of these items has a different important role to play

    what you need to remember is that minit and mshutdown are called in the opposite order that they are loaded, but you can’t depend on other extensions being around unless you have registered deps (remember way back in the main struct when we talked about deps?

    this flow is also true for prefork php webservers
    But then we get into threads
  • When we add threading it gets a little more difficult, because minit/mshutdown are only called when apache is restarted

    there’s also ginit and gshutdown but they’re broken

  • There are multiple declarations to help with this – the ZEND_STRS is a helper macro – again macro hell
  • So this has ONLY the basics – explain how the minit works
    then let’s talk lifecycle
  • Class constants are another thing that’s pretty easy to do – global constants are evil, do NOT do
  • then we add some constants for fun
  • Now let’s make our extension like… actually do something
  • Methods have several components but look very close to functions that we did earlier. There is a getThis which is available inside that will give you the zval for the class

    notice how similar this is to functions!
  • go over the method stuff just a bit
  • getTHis is the way you get “this” – notice that no matter how you declare your properties in MINIT, you can “juggle” the vale around depending on what you set it to
  • go over the method stuff just a bit
  • Note – traits in extensions are basically broken 
  • these are some more advanced topics
  • A PHP extension's globals are more properly called the "extension state", since most modules must remember what they're doing between function calls. The "counter" extension is a perfect example of this need: The basic interface calls for a counter with a persistent value. A programmer new to Zend and PHP might do something like this in counter.c to store that value:

  • efree, emalloc, ecalloc – you can find good documentation on these manual/en/internals2.memory.management.php

    zend is taking care of all the memory stuff for you – allocating a larger chunk, cleaning up at the end of the request (but still, efree dammit)

    Often, memory needs to be allocated for longer than the duration of a single request. These types of allocations, called persistent allocations because they persist beyond the end of a request, could be performed using the traditional memory allocators because these do not add the additional per-request information used by ZendMM. Sometimes, however, it's not known until runtime whether a particular allocation will need to be persistent or not, so ZendMM exports a set of helper macros that act just like the other memory allocation functions, but have an additional parameter at the end to indicate persistence.

    If you genuinely want a persistent allocation, this parameter should be set to one, in which case the request will be passed through to the traditional malloc() family of allocators. If runtime logic has determined that this block does not need to be persistent however, this parameter may be set to zero, and the call will be channeled to the perrequest memory allocator functions.
  • The new resources – generally if you need to pass around some kind of internal C pointer stuff, this is the way you do it

    so we define a struct that holds our boring zend_object AND any additional C magic thingies we need

    we’ll need a custom constructor for this – a C level constructor, that takes care of setting everything up, etc

    there’s a bunch more abo
  • you’ll do a lot of zend_fetch_object stuff to pick this stuff
  • these are all “magic” methods you can plug into at the C level (note that you can also provide standard __get, __set etc, but extending classes can override them)

    you can even do casting magic, closure magic, even meddle with gc stuff – but most people only really do the clone, debug info (for var_dump), and get/set property stuff
  • Why do you need to care about this? because of mod_apache!!!

    do you really need ot know how this works? no

    what DO You need to know – pass this stuff around, never use TSRMLS_FETCH – that is the evilest macro ever!

    PHP takes care of all of this for you – this is normally the HARD stuff

    rule of thumb #1 – stick an “e” in front of any memory stuff (emalloc, efree vs. malloc, free)
    Most of the time you won’t need to do much memory management, you’ll be using zend_parse_parameter stuff and zval manipulation which will do all of that for you – you MIGHT need it for whatever library your wrapping, but that can be very individualized
    TURN ON DEBUG, turn on crt debug (windows), turn on memory leak detection, compile with all errors, use static analysis if you can (clang, /analyze for windows, etc)
    all PHP_METHOD and PHP_FUNCTIO nstuff you’ll do has TSRMLS stuff in there – when you write your own functions in C you call from elsewhere PASS THAT DAMN THING ALONG – TSRMLS_FETCH should almost NEVER be used (unless you’re writing a threading extension and then – well good luck with that)
    PHP has a special way of doing globals in an extension that abstracts away the “owie” parts, USE IT – unless you need truly global globals and then you damn well better be locking them! (and you’re doing something crazy at that point)


    This will be moot in PHP7!!! were using thread local which takes care of all of this mess
  • Documentation is probably the most important part of the process, but I’ll still leave it for last

    If you’ve been writing examples and tests and protos and arginfo all along as I’ve whined about, you’re already 90 percent of the way there with docs, seriously

    the easiest way to do this would be to use a generator, however there aren’t any GOOD generators available right now

    so just go to svn and copy another extensions stuff – everything is created with PhD so you can test stuff

    for pecl you can

    put your code anywhere, for phpdoc you need to get your docs roughed out then ask them to be put in svn

    also mention readthedocs and the fact that pecl has licensing restrictions and we need a packagist
  • Go into here about how resources work (an integer pointer to a global table holding resources… or doing some other evil resource storage – basically you’re storing and throwing about pointers and they’re slow (DO NOT)

    ini entries are a horrible thing – the use cases are extremely small

    threading and such I can rant about for quite a bit

    and finally you can override parts of the engine from extensions – this is why xdebug and things like intercept work but they’re a bit beyond the scope of this talk
  • the project
    the goals
    the short history
    how to get involved
    how to make the extension ecosystem better
    pear vs. composer
    pickle vs. pecl
  • There is SOOO much more you can do from hooking objects to hooking the engine!
  • There is SOOO much more you can do from hooking objects to hooking the engine!

×