- URL: https://www.laruence.com/en/2008/08/22/412.html
- Please include attribution when republishing.
Maybe you know this, maybe you don't: PHP is a weakly typed, dynamic scripting language. Weak typing means PHP does not strictly verify variable types (strictly speaking, PHP is a moderately strong-typed language — I'll write about that in a later article). When you declare a variable, you don't need to explicitly state the type of the data it holds:
<?php
$var = 1; //int
$var = "laruence"; //string
$var = 1.0002; //float
$var = array(); // array
$var = new Exception('error'); //object;
A dynamic language means PHP's language constructs can change at runtime — for example, we can require a function definition file at runtime, which makes the language's function table change dynamically.
A scripting language means PHP does not run on its own; to run PHP we need a PHP parser:
/usr/bin/php -f example.php
As I've explained in my earlier articles, PHP executes through the Zend engine (ZE, Zend Engine), and ZE is written in C. As everyone knows, C is a strongly typed language — that is, in C every variable can only ever hold one type of data from the moment it is declared until it is finally destroyed. So how does PHP implement weak typing on top of ZE?
In PHP, every variable is stored in a single struct — zval. In Zend/zend.h we can see the definition of zval:
typedef struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
} zval;
zvalue_value is the key part that actually holds the data. Now the moment has come to reveal the answer: how does PHP implement weak typing on top of ZE? Because zvalue_value is a union,
typedef union _zvalue_value {
long lval;
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
} zvalue_value;
So how does this struct store the many types in PHP?
The common variable types in PHP are:
1. integer/float/long/bool, and so on 2. string 3. array/associative array 4. object 5. resource
PHP uses the type field in zval to store a variable's real type, and then picks how to fetch the value from zvalue_value according to type. For integers and bools, for example:
zval.type = IS_LONG;//integer zval.type = IS_BOOL;//bool
it fetches zval.value.lval; for a bool, lval ∈ (0|1);
if it's a double or float, it fetches zval.value.dval.
And if it's a string, then:
zval.type = IS_STRING
in that case, it fetches:
zval.value.str
which is itself a struct, holding a C-style string and the string's length.
For arrays and objects, type corresponds to IS_ARRAY and IS_OBJECT respectively, and we fetch zval.value.ht and obj accordingly.
Resources are rather special. In PHP a resource is a very peculiar variable: anything that isn't one of PHP's built-in variable types gets stored as a resource — a database handle, an open file handle, and so on. For a resource:
type = IS_RESOURCE
it fetches zval.value.lval. At this point lval is an integer index, and PHP then uses that index to look up the corresponding resource in a resource list built into PHP (I'll write a separate article about this later). For now, you only need to know that lval here works like an offset into the resource linked list.
ZEND_FETCH_RESOURCE(con, type, zval *, default, resource_name, resource_type);
Borrowing this mechanism, PHP achieves weak typing — because as far as ZE is concerned, it always faces the same single type: zval.
ps: My team is going out for a team building tomorrow, and I figured I should write something before I leave to help my blog readers kill the weekend. Today is just a simple start. Next time I'll go further into PHP variables, scope, and the copy on write and change on write mechanisms for variables. To be continued....
Be First to Comment