[{"data":1,"prerenderedAt":1270},["ShallowReactive",2],{"article:\u002Farticles\u002Fbuilding-a-65-million-item-array-in-php":3,"article-surround:\u002Farticles\u002Fbuilding-a-65-million-item-array-in-php":1264},{"id":4,"title":5,"body":6,"date":1252,"description":1253,"draft":1254,"extension":1255,"meta":1256,"navigation":146,"path":1257,"seo":1258,"stem":1259,"tags":1260,"__hash__":1263},"articles\u002Farticles\u002Fbuilding-a-65-million-item-array-in-php.md","How I Built a 65 Million Item Array in PHP... Kind Of",{"type":7,"value":8,"toc":1240},"minimark",[9,14,18,30,37,41,56,71,74,77,80,100,104,111,400,405,408,422,425,650,655,658,665,673,676,679,702,705,872,880,886,917,924,928,935,944,949,1023,1030,1073,1076,1079,1086,1090,1100,1103,1106,1110,1124,1127,1130,1133,1180,1183,1187,1190,1217,1220,1224,1227,1236],[10,11,13],"h2",{"id":12},"but-why","But Why?",[15,16,17],"p",{},"Arrays in PHP are great, flexible, dynamic, easy to work with, but I've always wondered how far they could really go. Whether it's Laravel Collections, plain arrays, or objects, I often find myself bumping into performance or memory limits.",[15,19,20,21,25,26,29],{},"So I decided to find out how far I could ",[22,23,24],"em",{},"really"," push them.\nI'm an avid C developer (without ",[22,27,28],{},"much"," C experience, you know how that goes), and I wanted to peek under the hood to learn how PHP handles its internal data structures.",[15,31,32,33,36],{},"Spoiler alert: I didn't use PHP arrays.",[34,35],"br",{},"\nI used C structs.",[10,38,40],{"id":39},"why-are-php-arrays-so-heavy","Why Are PHP Arrays So Heavy?",[15,42,43,44,48,49,51,52,55],{},"PHP arrays are wonderful to use, but they're ",[45,46,47],"strong",{},"not"," memory efficient.",[34,50],{},"\nThat's because, under the hood, arrays in PHP are implemented as ",[45,53,54],{},"hash tables",".",[15,57,58,59,62,63,67,68,55],{},"A hash table isn't just a flat block of memory like in C. It's a complex data structure that maps keys to values by computing a ",[22,60,61],{},"hash"," (a deterministic number) for each key. This makes associative arrays possible, so we can do ",[64,65,66],"code",{},"$user['id']"," instead of ",[64,69,70],{},"$user[0]",[15,72,73],{},"But that flexibility comes at a cost: every key\u002Fvalue pair involves extra bookkeeping, memory for hashes, pointers, type metadata, and reference counts. It's great for ergonomics, not for density.",[15,75,76],{},"Objects in PHP are similar: they're also built around hash tables internally, though the Zend Engine optimises access by simulating a \"struct-like\" layout for class properties.",[15,78,79],{},"If you're curious, you can see this in the Zend source code (warning: requires reading C):",[81,82,83,93],"ul",{},[84,85,86],"li",{},[87,88,92],"a",{"href":89,"rel":90},"https:\u002F\u002Fgithub.com\u002Fphp\u002Fphp-src\u002Fblob\u002Fmaster\u002FZend\u002Fzend_hash.c",[91],"nofollow","zend_hash.c",[84,94,95],{},[87,96,99],{"href":97,"rel":98},"https:\u002F\u002Fgithub.com\u002Fphp\u002Fphp-src\u002Fblob\u002Fmaster\u002FZend\u002Fzend_objects.c",[91],"zend_objects.c",[10,101,103],{"id":102},"enter-ffi-the-bridge-between-php-and-c","Enter FFI - The Bridge Between PHP and C",[15,105,106,107,110],{},"In C, the language PHP itself is built on, you have ",[45,108,109],{},"structs",", which are contiguous blocks of memory containing fixed, typed fields. This layout is incredibly efficient, especially for large datasets.",[112,113,118],"pre",{"className":114,"code":115,"language":116,"meta":117,"style":117},"language-c shiki shiki-themes github-dark github-light","#include \u003Cstdio.h>\n#include \u003Cstring.h>\n\n\u002F\u002F Define a struct to represent a person\ntypedef struct {\n    int id;\n    char name[50];\n    float height;\n} Person;\n\nint main(void) {\n    \u002F\u002F Declare a struct variable\n    Person alice;\n\n    \u002F\u002F Assign values to its fields\n    alice.id = 1;\n    strcpy(alice.name, \"Alice\");\n    alice.height = 1.68f;\n\n    \u002F\u002F Access and print fields\n    printf(\"ID: %d\\n\", alice.id);\n    printf(\"Name: %s\\n\", alice.name);\n    printf(\"Height: %.2f m\\n\", alice.height);\n\n    return 0;\n}\n","c","",[64,119,120,133,141,148,155,168,177,197,206,212,217,236,242,248,253,259,274,289,305,310,316,336,354,378,383,394],{"__ignoreMap":117},[121,122,125,129],"span",{"class":123,"line":124},"line",1,[121,126,128],{"class":127},"spKkM","#include",[121,130,132],{"class":131},"skb7c"," \u003Cstdio.h>\n",[121,134,136,138],{"class":123,"line":135},2,[121,137,128],{"class":127},[121,139,140],{"class":131}," \u003Cstring.h>\n",[121,142,144],{"class":123,"line":143},3,[121,145,147],{"emptyLinePlaceholder":146},true,"\n",[121,149,151],{"class":123,"line":150},4,[121,152,154],{"class":153},"si27w","\u002F\u002F Define a struct to represent a person\n",[121,156,158,161,164],{"class":123,"line":157},5,[121,159,160],{"class":127},"typedef",[121,162,163],{"class":127}," struct",[121,165,167],{"class":166},"shWlK"," {\n",[121,169,171,174],{"class":123,"line":170},6,[121,172,173],{"class":127},"    int",[121,175,176],{"class":166}," id;\n",[121,178,180,183,187,190,194],{"class":123,"line":179},7,[121,181,182],{"class":127},"    char",[121,184,186],{"class":185},"sdxZB"," name",[121,188,189],{"class":166},"[",[121,191,193],{"class":192},"sTU5a","50",[121,195,196],{"class":166},"];\n",[121,198,200,203],{"class":123,"line":199},8,[121,201,202],{"class":127},"    float",[121,204,205],{"class":166}," height;\n",[121,207,209],{"class":123,"line":208},9,[121,210,211],{"class":166},"} Person;\n",[121,213,215],{"class":123,"line":214},10,[121,216,147],{"emptyLinePlaceholder":146},[121,218,220,223,227,230,233],{"class":123,"line":219},11,[121,221,222],{"class":127},"int",[121,224,226],{"class":225},"sqoU-"," main",[121,228,229],{"class":166},"(",[121,231,232],{"class":127},"void",[121,234,235],{"class":166},") {\n",[121,237,239],{"class":123,"line":238},12,[121,240,241],{"class":153},"    \u002F\u002F Declare a struct variable\n",[121,243,245],{"class":123,"line":244},13,[121,246,247],{"class":166},"    Person alice;\n",[121,249,251],{"class":123,"line":250},14,[121,252,147],{"emptyLinePlaceholder":146},[121,254,256],{"class":123,"line":255},15,[121,257,258],{"class":153},"    \u002F\u002F Assign values to its fields\n",[121,260,262,265,268,271],{"class":123,"line":261},16,[121,263,264],{"class":166},"    alice.id ",[121,266,267],{"class":127},"=",[121,269,270],{"class":192}," 1",[121,272,273],{"class":166},";\n",[121,275,277,280,283,286],{"class":123,"line":276},17,[121,278,279],{"class":225},"    strcpy",[121,281,282],{"class":166},"(alice.name, ",[121,284,285],{"class":131},"\"Alice\"",[121,287,288],{"class":166},");\n",[121,290,292,295,297,300,303],{"class":123,"line":291},18,[121,293,294],{"class":166},"    alice.height ",[121,296,267],{"class":127},[121,298,299],{"class":192}," 1.68",[121,301,302],{"class":127},"f",[121,304,273],{"class":166},[121,306,308],{"class":123,"line":307},19,[121,309,147],{"emptyLinePlaceholder":146},[121,311,313],{"class":123,"line":312},20,[121,314,315],{"class":153},"    \u002F\u002F Access and print fields\n",[121,317,319,322,324,327,330,333],{"class":123,"line":318},21,[121,320,321],{"class":225},"    printf",[121,323,229],{"class":166},[121,325,326],{"class":131},"\"ID: ",[121,328,329],{"class":192},"%d\\n",[121,331,332],{"class":131},"\"",[121,334,335],{"class":166},", alice.id);\n",[121,337,339,341,343,346,349,351],{"class":123,"line":338},22,[121,340,321],{"class":225},[121,342,229],{"class":166},[121,344,345],{"class":131},"\"Name: ",[121,347,348],{"class":192},"%s\\n",[121,350,332],{"class":131},[121,352,353],{"class":166},", alice.name);\n",[121,355,357,359,361,364,367,370,373,375],{"class":123,"line":356},23,[121,358,321],{"class":225},[121,360,229],{"class":166},[121,362,363],{"class":131},"\"Height: ",[121,365,366],{"class":192},"%.2f",[121,368,369],{"class":131}," m",[121,371,372],{"class":192},"\\n",[121,374,332],{"class":131},[121,376,377],{"class":166},", alice.height);\n",[121,379,381],{"class":123,"line":380},24,[121,382,147],{"emptyLinePlaceholder":146},[121,384,386,389,392],{"class":123,"line":385},25,[121,387,388],{"class":127},"    return",[121,390,391],{"class":192}," 0",[121,393,273],{"class":166},[121,395,397],{"class":123,"line":396},26,[121,398,399],{"class":166},"}\n",[15,401,402],{},[22,403,404],{},"Example of implementing structs within C",[15,406,407],{},"Wouldn't it be great if PHP could use those same C structs directly?",[15,409,410,411,413,414,417,418,421],{},"It turns out, it can.",[34,412],{},"\nEnter ",[45,415,416],{},"FFI",", ",[22,419,420],{},"Foreign Function Interface",", which allows PHP to call directly into C code and allocate native memory.",[15,423,424],{},"FFI is powerful, but it's also risky. You can poke directly into memory, forget to free it, or crash PHP entirely if you're not careful. In other words: great power, great responsibility (and maybe a segfault or two).",[112,426,430],{"className":427,"code":428,"language":429,"meta":117,"style":117},"language-php shiki shiki-themes github-dark github-light","\u003C?php\n\n\u002F\u002F Define the struct layout using C syntax\n$typedef = \"\ntypedef struct {\n    int id;\n    float value;\n} Record;\n\";\n\n\u002F\u002F Create the FFI binding for this definition\n$ffi = FFI::cdef($typedef);\n\n\u002F\u002F Allocate a new struct instance\n$record = $ffi->new(\"Record\");\n\n\u002F\u002F Assign values to its fields\n$record->id = 42;\n$record->value = 3.14;\n\n\u002F\u002F Access and print the values\necho \"ID: {$record->id}\\n\";        \u002F\u002F ID: 42\necho \"Value: {$record->value}\\n\";  \u002F\u002F Value: 3.14\n\n","php",[64,431,432,440,444,449,459,464,469,474,479,485,489,494,513,517,522,545,549,554,571,587,591,596,624],{"__ignoreMap":117},[121,433,434,437],{"class":123,"line":124},[121,435,436],{"class":127},"\u003C?",[121,438,439],{"class":192},"php\n",[121,441,442],{"class":123,"line":135},[121,443,147],{"emptyLinePlaceholder":146},[121,445,446],{"class":123,"line":143},[121,447,448],{"class":153},"\u002F\u002F Define the struct layout using C syntax\n",[121,450,451,454,456],{"class":123,"line":150},[121,452,453],{"class":166},"$typedef ",[121,455,267],{"class":127},[121,457,458],{"class":131}," \"\n",[121,460,461],{"class":123,"line":157},[121,462,463],{"class":131},"typedef struct {\n",[121,465,466],{"class":123,"line":170},[121,467,468],{"class":131},"    int id;\n",[121,470,471],{"class":123,"line":179},[121,472,473],{"class":131},"    float value;\n",[121,475,476],{"class":123,"line":199},[121,477,478],{"class":131},"} Record;\n",[121,480,481,483],{"class":123,"line":208},[121,482,332],{"class":131},[121,484,273],{"class":166},[121,486,487],{"class":123,"line":214},[121,488,147],{"emptyLinePlaceholder":146},[121,490,491],{"class":123,"line":219},[121,492,493],{"class":153},"\u002F\u002F Create the FFI binding for this definition\n",[121,495,496,499,501,504,507,510],{"class":123,"line":238},[121,497,498],{"class":166},"$ffi ",[121,500,267],{"class":127},[121,502,503],{"class":192}," FFI",[121,505,506],{"class":127},"::",[121,508,509],{"class":225},"cdef",[121,511,512],{"class":166},"($typedef);\n",[121,514,515],{"class":123,"line":244},[121,516,147],{"emptyLinePlaceholder":146},[121,518,519],{"class":123,"line":250},[121,520,521],{"class":153},"\u002F\u002F Allocate a new struct instance\n",[121,523,524,527,529,532,535,538,540,543],{"class":123,"line":255},[121,525,526],{"class":166},"$record ",[121,528,267],{"class":127},[121,530,531],{"class":166}," $ffi",[121,533,534],{"class":127},"->",[121,536,537],{"class":225},"new",[121,539,229],{"class":166},[121,541,542],{"class":131},"\"Record\"",[121,544,288],{"class":166},[121,546,547],{"class":123,"line":261},[121,548,147],{"emptyLinePlaceholder":146},[121,550,551],{"class":123,"line":276},[121,552,553],{"class":153},"\u002F\u002F Assign values to its fields\n",[121,555,556,559,561,564,566,569],{"class":123,"line":291},[121,557,558],{"class":166},"$record",[121,560,534],{"class":127},[121,562,563],{"class":166},"id ",[121,565,267],{"class":127},[121,567,568],{"class":192}," 42",[121,570,273],{"class":166},[121,572,573,575,577,580,582,585],{"class":123,"line":307},[121,574,558],{"class":166},[121,576,534],{"class":127},[121,578,579],{"class":166},"value ",[121,581,267],{"class":127},[121,583,584],{"class":192}," 3.14",[121,586,273],{"class":166},[121,588,589],{"class":123,"line":312},[121,590,147],{"emptyLinePlaceholder":146},[121,592,593],{"class":123,"line":318},[121,594,595],{"class":153},"\u002F\u002F Access and print the values\n",[121,597,598,601,604,606,608,611,614,616,618,621],{"class":123,"line":338},[121,599,600],{"class":192},"echo",[121,602,603],{"class":131}," \"ID: {",[121,605,558],{"class":166},[121,607,534],{"class":127},[121,609,610],{"class":166},"id",[121,612,613],{"class":131},"}",[121,615,372],{"class":192},[121,617,332],{"class":131},[121,619,620],{"class":166},";        ",[121,622,623],{"class":153},"\u002F\u002F ID: 42\n",[121,625,626,628,631,633,635,638,640,642,644,647],{"class":123,"line":356},[121,627,600],{"class":192},[121,629,630],{"class":131}," \"Value: {",[121,632,558],{"class":166},[121,634,534],{"class":127},[121,636,637],{"class":166},"value",[121,639,613],{"class":131},[121,641,372],{"class":192},[121,643,332],{"class":131},[121,645,646],{"class":166},";  ",[121,648,649],{"class":153},"\u002F\u002F Value: 3.14\n",[15,651,652],{},[22,653,654],{},"Example of implementing C-like structs within PHP",[15,656,657],{},"This is a great start, but let's see if we can extend it further!",[15,659,660,661],{},"You can read more about FFI here: ",[87,662,663],{"href":663,"rel":664},"https:\u002F\u002Fwww.php.net\u002Fmanual\u002Fen\u002Fbook.ffi.php",[91],[10,666,668,669,672],{"id":667},"building-a-struct-class","Building a ",[64,670,671],{},"Struct"," Class",[15,674,675],{},"I wanted a way to use C structs safely from PHP, so I wrote a small library that wraps FFI in a familiar object-oriented interface.",[15,677,678],{},"The idea:",[81,680,681,688,691],{},[84,682,683,684,687],{},"Define your C ",[64,685,686],{},"typedef struct"," in a string",[84,689,690],{},"Create an array of those structs",[84,692,693,694,697,698,701],{},"Interact with it using ",[64,695,696],{},"set()"," and ",[64,699,700],{},"get()"," methods",[15,703,704],{},"Here's what that looks like in practice:",[112,706,708],{"className":427,"code":707,"language":429,"meta":117,"style":117},"$typedef = \"\ntypedef struct {\n    int id;\n    float value;\n} Record;\n\";\n\n$count = 100_000;\n$records = new Struct($typedef, \"Record\", $count);\n\nfor ($i = 0; $i \u003C $count; $i++) {\n    $records->set($i, ['id' => $i, 'value' => (float)$i]);\n}\n\n$record = $records->get(0);\n",[64,709,710,718,722,726,730,734,740,744,756,777,781,807,843,847,851],{"__ignoreMap":117},[121,711,712,714,716],{"class":123,"line":124},[121,713,453],{"class":166},[121,715,267],{"class":127},[121,717,458],{"class":131},[121,719,720],{"class":123,"line":135},[121,721,463],{"class":131},[121,723,724],{"class":123,"line":143},[121,725,468],{"class":131},[121,727,728],{"class":123,"line":150},[121,729,473],{"class":131},[121,731,732],{"class":123,"line":157},[121,733,478],{"class":131},[121,735,736,738],{"class":123,"line":170},[121,737,332],{"class":131},[121,739,273],{"class":166},[121,741,742],{"class":123,"line":179},[121,743,147],{"emptyLinePlaceholder":146},[121,745,746,749,751,754],{"class":123,"line":199},[121,747,748],{"class":166},"$count ",[121,750,267],{"class":127},[121,752,753],{"class":192}," 100_000",[121,755,273],{"class":166},[121,757,758,761,763,766,769,772,774],{"class":123,"line":208},[121,759,760],{"class":166},"$records ",[121,762,267],{"class":127},[121,764,765],{"class":127}," new",[121,767,768],{"class":192}," Struct",[121,770,771],{"class":166},"($typedef, ",[121,773,542],{"class":131},[121,775,776],{"class":166},", $count);\n",[121,778,779],{"class":123,"line":214},[121,780,147],{"emptyLinePlaceholder":146},[121,782,783,786,789,791,793,796,799,802,805],{"class":123,"line":219},[121,784,785],{"class":127},"for",[121,787,788],{"class":166}," ($i ",[121,790,267],{"class":127},[121,792,391],{"class":192},[121,794,795],{"class":166},"; $i ",[121,797,798],{"class":127},"\u003C",[121,800,801],{"class":166}," $count; $i",[121,803,804],{"class":127},"++",[121,806,235],{"class":166},[121,808,809,812,814,817,820,823,826,829,832,834,837,840],{"class":123,"line":238},[121,810,811],{"class":166},"    $records",[121,813,534],{"class":127},[121,815,816],{"class":225},"set",[121,818,819],{"class":166},"($i, [",[121,821,822],{"class":131},"'id'",[121,824,825],{"class":127}," =>",[121,827,828],{"class":166}," $i, ",[121,830,831],{"class":131},"'value'",[121,833,825],{"class":127},[121,835,836],{"class":166}," (",[121,838,839],{"class":127},"float",[121,841,842],{"class":166},")$i]);\n",[121,844,845],{"class":123,"line":244},[121,846,399],{"class":166},[121,848,849],{"class":123,"line":250},[121,850,147],{"emptyLinePlaceholder":146},[121,852,853,855,857,860,862,865,867,870],{"class":123,"line":255},[121,854,526],{"class":166},[121,856,267],{"class":127},[121,858,859],{"class":166}," $records",[121,861,534],{"class":127},[121,863,864],{"class":225},"get",[121,866,229],{"class":166},[121,868,869],{"class":192},"0",[121,871,288],{"class":166},[15,873,874],{},[22,875,876,877,879],{},"Example of using homebrewed ",[64,878,671],{}," class",[15,881,882,883,885],{},"Under the hood, the ",[64,884,671],{}," class:",[81,887,888,895,902,909],{},[84,889,890,891,894],{},"Calls ",[64,892,893],{},"FFI::cdef()"," to define the struct",[84,896,897,898,901],{},"Allocates a contiguous array (",[64,899,900],{},"new Type[N]",")",[84,903,904,905,908],{},"Uses PHP's garbage collector for cleanup (you ",[22,906,907],{},"can"," manage memory manually, but proceed at your own risk)",[84,910,911,912,417,914,916],{},"Exposes safe methods like ",[64,913,696],{},[64,915,700],{},", iteration helpers, and size reporting",[15,918,919,920],{},"You can find the code on GitHub as a Composer package:\n",[87,921,922],{"href":922,"rel":923},"https:\u002F\u002Fgithub.com\u002Frayblair06\u002Fphp-struct",[91],[10,925,927],{"id":926},"results-structs-vs-arrays-vs-objects","Results: Structs vs Arrays vs Objects",[15,929,930,931,697,933,55],{},"For this benchmark, I used a simple data structure with two fields: ",[64,932,610],{},[64,934,637],{},[15,936,937,938,55,941,943],{},"With a 512 MB memory limit, I was able to generate roughly ",[45,939,940],{},"65 million struct entries",[34,942],{},"\nTrying to achieve the same with arrays or objects? PHP taps out far earlier.",[15,945,946],{},[45,947,948],{},"Approximate limits:",[950,951,952,968],"table",{},[953,954,955],"thead",{},[956,957,958,962,965],"tr",{},[959,960,961],"th",{},"Type",[959,963,964],{},"Items",[959,966,967],{},"Notes",[969,970,971,985,999,1010],"tbody",{},[956,972,973,979,982],{},[974,975,976,978],"td",{},[64,977,671],{}," (FFI)",[974,980,981],{},"~65 million",[974,983,984],{},"contiguous C memory",[956,986,987,993,996],{},[974,988,989,990,901],{},"Object (",[64,991,992],{},"RecordClass",[974,994,995],{},"~4.1 million",[974,997,998],{},"each has its own zval\u002Fobject overhead",[956,1000,1001,1004,1007],{},[974,1002,1003],{},"Array",[974,1005,1006],{},"~1.4 million",[974,1008,1009],{},"hash table storage",[956,1011,1012,1017,1020],{},[974,1013,989,1014,901],{},[64,1015,1016],{},"stdClass",[974,1018,1019],{},"~1 million",[974,1021,1022],{},"dynamic property storage",[15,1024,1025,1026,1029],{},"For a smaller test with ",[45,1027,1028],{},"500,000"," items:",[950,1031,1032,1041],{},[953,1033,1034],{},[956,1035,1036,1038],{},[959,1037,961],{},[959,1039,1040],{},"Memory Used",[969,1042,1043,1050,1057,1064],{},[956,1044,1045,1047],{},[974,1046,671],{},[974,1048,1049],{},"~4 MB",[956,1051,1052,1054],{},[974,1053,992],{},[974,1055,1056],{},"~52 MB",[956,1058,1059,1061],{},[974,1060,1003],{},[974,1062,1063],{},"~197 MB",[956,1065,1066,1070],{},[974,1067,1068],{},[64,1069,1016],{},[974,1071,1072],{},"~253 MB",[15,1074,1075],{},"All this raw power comes with trade-offs: C structs are fixed-type (no strings), require manual field handling, and can't represent complex data structures.",[15,1077,1078],{},"In other words:\nPHP arrays give you flexibility, structs give you raw performance. You can't have both... at least, not yet.",[15,1080,1081,1082],{},"You can see the full benchmark implementation here: ",[87,1083,1084],{"href":1084,"rel":1085},"https:\u002F\u002Fgithub.com\u002Frayblair06\u002Fphp-struct\u002Fblob\u002Fmain\u002Fbin\u002Fbenchmarks.php",[91],[10,1087,1089],{"id":1088},"why-does-this-matter","Why Does This Matter?",[15,1091,1092,1093,1095,1096,1099],{},"Honestly? It doesn't.",[34,1094],{},"\nAt least not for your average application. You're probably not handling ",[45,1097,1098],{},"65 million"," array items, and if you are, you're likely using lazy iteration, streams, buffers, or another architecture designed for that scale. But if you can't, knowing this might just help.",[15,1101,1102],{},"This was mostly a for-science experiment to see how PHP's internals behave when you cut out the abstraction layers. You lose many of PHP's conveniences, type flexibility, automatic resizing, string safety, and gain a lot of sharp edges (like floating-point precision differences and endian quirks).",[15,1104,1105],{},"Still, it's a fascinating way to explore how PHP memory really works, and it shows that PHP's FFI gives you the keys to drive right into C territory.",[10,1107,1109],{"id":1108},"what-i-learned","What I Learned",[81,1111,1112,1115,1118,1121],{},[84,1113,1114],{},"How PHP's memory model and arrays work under the hood",[84,1116,1117],{},"How FFI bridges PHP and C in a surprisingly powerful way",[84,1119,1120],{},"Why PHP arrays are magical but expensive",[84,1122,1123],{},"How fun it is to (responsibly) abuse FFI 😄",[15,1125,1126],{},"I learned a whole lot about low-level concepts and the internal workings of the PHP language, but this only feels like scratching the surface.",[15,1128,1129],{},"It's worth saying these aren't new problems, and there are extensions that expose lower-level behaviour without needing to dive into C yourself.",[15,1131,1132],{},"For example:",[81,1134,1135,1155,1174],{},[84,1136,1137,1143,1144,417,1147,1150,1151,1154],{},[45,1138,1139,1142],{},[64,1140,1141],{},"ext\u002Fspl"," (Standard PHP Library)"," offers data structures like ",[64,1145,1146],{},"SplFixedArray",[64,1148,1149],{},"SplHeap",", and ",[64,1152,1153],{},"SplObjectStorage"," that provide more predictable memory usage than regular arrays.",[84,1156,1157,1163,1164,417,1167,1150,1170,1173],{},[45,1158,1159,1162],{},[64,1160,1161],{},"ext\u002Fds"," (Data Structures)"," goes a step further, adding efficient collections such as ",[64,1165,1166],{},"Vector",[64,1168,1169],{},"Map",[64,1171,1172],{},"Deque"," - all written in C for performance.",[84,1175,1176,1177,1179],{},"And of course, ",[45,1178,416],{}," itself lets you bridge directly into C, opening the door to everything from native libraries to raw memory access.",[15,1181,1182],{},"Exploring these extensions shows how PHP gives developers different levels of abstraction depending on what they need, from high-level collections for everyday work, to FFI and Zend internals for those who want to tinker with memory and performance.",[10,1184,1186],{"id":1185},"where-this-could-go-next","Where This Could Go Next",[15,1188,1189],{},"This experiment opens a few interesting doors:",[81,1191,1192,1199,1205,1211],{},[84,1193,1194,1195,1198],{},"A ",[45,1196,1197],{},"native PHP extension"," for faster struct handling",[84,1200,1201,1204],{},[45,1202,1203],{},"Shared-memory structs"," for interprocess data",[84,1206,1207,1210],{},[45,1208,1209],{},"File-mapped buffers"," for huge datasets",[84,1212,1213,1216],{},[45,1214,1215],{},"Typed arrays"," that blend PHP syntax with native memory performance",[15,1218,1219],{},"Or, like many great side projects, it might just rot in my GitHub, never to see the light of day again.",[10,1221,1223],{"id":1222},"closing","Closing",[15,1225,1226],{},"You can think of this as PHP meeting C halfway, bringing the predictability and memory efficiency of C structs into a high-level, dynamic environment.",[15,1228,1229,1230,1232,1233,1235],{},"I didn't make PHP faster.",[34,1231],{},"\nI didn't break it (mostly).",[34,1234],{},"\nBut I did build a 65 million-item array... kind of.",[1237,1238,1239],"style",{},"html pre.shiki code .spKkM, html code.shiki .spKkM{--shiki-default:#F97583;--shiki-light:#D73A49}html pre.shiki code .skb7c, html code.shiki .skb7c{--shiki-default:#9ECBFF;--shiki-light:#032F62}html pre.shiki code .si27w, html code.shiki .si27w{--shiki-default:#6A737D;--shiki-light:#6A737D}html pre.shiki code .shWlK, html code.shiki .shWlK{--shiki-default:#E1E4E8;--shiki-light:#24292E}html pre.shiki code .sdxZB, html code.shiki .sdxZB{--shiki-default:#FFAB70;--shiki-light:#E36209}html pre.shiki code .sTU5a, html code.shiki .sTU5a{--shiki-default:#79B8FF;--shiki-light:#005CC5}html pre.shiki code .sqoU-, html code.shiki .sqoU-{--shiki-default:#B392F0;--shiki-light:#6F42C1}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":117,"searchDepth":135,"depth":135,"links":1241},[1242,1243,1244,1245,1247,1248,1249,1250,1251],{"id":12,"depth":135,"text":13},{"id":39,"depth":135,"text":40},{"id":102,"depth":135,"text":103},{"id":667,"depth":135,"text":1246},"Building a Struct Class",{"id":926,"depth":135,"text":927},{"id":1088,"depth":135,"text":1089},{"id":1108,"depth":135,"text":1109},{"id":1185,"depth":135,"text":1186},{"id":1222,"depth":135,"text":1223},"2025-11-01","Why PHP arrays are secretly memory-hungry hash tables - and how I used FFI and C structs to fit 65 million items into memory anyway.",false,"md",{},"\u002Farticles\u002Fbuilding-a-65-million-item-array-in-php",{"title":5,"description":1253},"articles\u002Fbuilding-a-65-million-item-array-in-php",[429,1261,1262],"performance","memory","MPM-vk24p4VoCGUFyrPr9cIzk_I2l6kLEEJD-wHi6-8",[1265,1266],null,{"title":1267,"path":1268,"stem":1269,"children":-1},"Clean Architecture for PHP Applications","\u002Farticles\u002Fclean-architecture-for-php-applications","articles\u002Fclean-architecture-for-php-applications",1782332463146]