$30 off During Our Annual Pro Sale. View Details »

php_mecabをFFIで実装してみよう

 php_mecabをFFIで実装してみよう

PHPカンファレンス2022の発表資料です。
かつて自分がPHP MeCab Extensionを実装したときはC言語でバインディングを書くのが一般的な方法でした。
しかしPHP 7.4からはFFI (Foreign Function Interface) が導入され、C言語を書かなくてもC言語で書かれたライブラリが利用できるようになりました。
php_mecabをFFIを使って再実装する実例を元に、以下の解説をします。
・FFIの基本的な使い方
・メモリ管理
・FFIでできること
・FFIでできないこと

Ryusuke SEKIYAMA

September 25, 2022
Tweet

More Decks by Ryusuke SEKIYAMA

Other Decks in Programming

Transcript

  1. גࣜձࣾ3"#0ؔࢁོհ5XJUUFS!STLZ QIQ@NFDBCΛ ''*Ͱ࠶࣮૷ͯ͠ΈΑ͏ 1)1$POGFSFODF 5SBDL

  2. ࠶࣮૷ 
 Ͱ͖·ͨ͠ IUUQTHJUIVCDPNSTLZQIQ ff i NFDBC

  3. ؔࢁོհ ͖ͤ΍·ΓΎ͏͚͢ !STLZ w ͔ͭͯ$ݴޠͰ࣮૷ͨ͠ 
 QIQ@NFDBCΛ࡞͍ͬͯ·ͨ͠ w ࡢ೥݄ʹ3"#0 *ODʹస৬

    
 $BUMPHͷόοΫΤϯυ୲౰ w ͻ͞ͼ͞ʹ࢓ࣄͰ1)1Λ࢖ͬͯ 
 ͍·͢ 1)1 4ZNGPOZ  w ͣͬͱ࣮Ոʹݘ͕͍ͨͷͰݘ೿ w ೣ΋େ޷͖ 4PGUXBSF%FTJHOࢽͷදࢴྑ͍Ͱ͢Ͷ ࣗݾ঺հ Ωϟτϩά
  4. .F$BCͱ͸

  5. .F$BCͱ͸ IUUQTUBLVHJUIVCJPNFDBC w ΦʔϓϯιʔεͷܗଶૉղੳΤϯδϯ w ߴ଎ͳಈ࡞ɺߴ͍҆ఆੑɺѻ͍΍͍͢"1*͕ૉఢ w .Z42-ͷશจݕࡧΠϯσοΫε༻ύʔαʔʹ࠾༻͞ΕΔͳͲɺ๛෋ͳ࣮੷

  6. ''*ͱ͸

  7. ग़యϑϦʔඦՊࣄయʰ΢ΟΩϖσΟΞʢ8JLJQFEJBʣʱ 'PSFJHOGVODUJPOJOUFSGBDFʢϑΥʔϦϯɾϑΝϯΫγϣϯɾΠϯλʔϑΣΠεɺ ''*ʣͱ͸ɺ͋Δϓϩάϥϛϯάݴޠ͔ΒଞͷϓϩάϥϛϯάݴޠͰఆٛ͞Εͨؔ਺ͳ ͲΛར༻͢ΔͨΊͷػߏɻओʹߴਫ४ݴޠ͔Β$$ ͳͲͷؔ਺΍ϝιουΛݺͼग़ ͠ɺ04ݻ༗ͷػೳͳͲΛར༻͢ΔͨΊʹ࢖༻͞ΕΔ͜ͱ͕ଟ͍ɻ

  8. 1)1ͷ''*ͱ͸

  9. 1)1''* ΠϯτϩμΫγϣϯ w 1)1͔Βಋೖ w IUUQTXXXQIQOFU f  w $ݴޠͷ"1*Λ1VSF1)1ίʔυ͔Βݺͼग़ͤΔ

    w $ݴޠҎ֎ͷϥΠϒϥϦʹ͸ඇରԠ w 3VTU΍(P౳ɺ$ݴޠ޲͚ͷڞ༗ϥΠϒϥϦΛ 
 ࡞ΕΔݴޠͰ࡞ͬͨؔ਺͸0,
  10. 1)1ϚχϡΞϧΑΓ w 1VSF1)1Ͱ$ؔ਺΍ߏ଄ମʹ ΞΫηεͰ͖ΔΑ w ;FOEFYUFOTJPO"1*ͷ஌ࣝ͸ ͍Βͳ͍Αʢॏཁʣ w $ݴޠͷ஌͕ࣝ͋Δਓ޲͚ͩΑ w

    طଘͷ1)1֦ு"1*Λஔ͖׵͑ ΔΑ͏ͳ΋ͷͰ͸ͳ͍Α 1)1''*
  11. 1)1''* ;FOEFYUFOTJPO"1* $ݴޠͰॻ͘1)1ػೳ֦ு ͱൺֱ ''* ;FOEFYUFOTJPO"1* ֎෦ϥΠϒϥϦͷར༻ Ͱ͖Δ Ͱ͖Δ 1)1ͦͷ΋ͷͷৼΔ෣͍มߋ

    Ͱ͖ͳ͍ Ͱ͖Δ $ݴޠͷ஌ࣝ ඞཁ ඞཁ Ϗϧυ༻πʔϧνΣʔϯ ίϯύΠϥɾϦϯΧ౳ ෆཁ ඞཁ 1)1ͷόʔδϣϯΞοϓରԠ ෆཁ ˞''*ʹഁյతͳมߋ͕ೖΒͳ͍ݶΓ͸ ඞཁ
  12. جຊతͳ࢖͍ํ  ϥΠϒϥϦͷϔομϑΝΠϧ͔Β࢖͍͍ͨ ίʔυΛநग़ w ϚΫϩ͸ޮ͔ͳ͍ͷͰ஫ҙʂ  FFI::cdef()Ͱ''*ΦϒδΣΫτΛੜ੒ w ୈҾ਺͸ڞ༗ϥΠϒϥϦͷύε

     ''*ΦϒδΣΫτͷϝιουͱͯؔ͠਺Λ ݺͼग़͢  Ҏ্ʂ 1)1''*
  13. w $ͷߏ଄ମ͸FFI\CDataΦϒδ ΣΫτʹϚοϐϯά͞ΕΔ w ߏ଄ମͷϝϯό͸$%BUBΦϒδ ΣΫτͷΦʔόʔϩʔυ͞Εͨ ϓϩύςΟͱͯ͠ΞΫηεͰ͖Δ w FFI::new(T)͸ malloc(sizeof(T))૬౰

    1)1''* ߏ଄ମͷαϙʔτ
  14. ࣮ફ5JQT

  15. $ݴޠͷίʔυ͸ִ཭ w ࢖͍͍ͨػೳ͕গͳ͍ͳΒ໰୊ ͳ͍͕ɺେ͖ͳϥΠϒϥϦΛϥο ϓ͠Α͏ͱ͢Δͱ$ͷίʔυྔ͕ ଟ͘ͳͬͯݟ௨͕͠ѱ͘ͳΔ w ઐ༻ͷϑΝΠϧʹִ཭͢Δͷ΋Ξ ϦͰ͸ ࣮ફ5JQT

  16. จࣈྻͷ഑ྻ w $ؔ਺ʹ౉͢จࣈྻͷ഑ྻ͸ࣗલͰ࡞Δඞཁ͋Γ w ӈͷྫͰ͸FFI::arrayType()Λ࢖ͬͯchar *ͷ࣍ݩ഑ྻΛ࡞੒ w 1)1ͷจࣈྻΛPXOFEͰͳ͍$%BUBʹม׵͠ ͯ഑ྻʹ٧ΊΔ w

    "SSBZ5ZQF͸ͦͷཁૉͷॴ༗ݖΛ࣋ͨͳ͍ ʢ࣋ͯͳ͍ʣͨΊ w 1)1Ͱ͸ීஈҙࣝ͠ͳ͍ψϧऴ୺Λ͖ͬͪΓͱ w 0XOFEͰͳ͍FFI::new()ͨ͠$%BUB͸ࣗ෼ ͰFFI::free()͢Δ ࣮ફ5JQT
  17. w ܕͷͳ͍FFI\CDataͷΦʔόʔϩʔυ͞ ΕͨϓϩύςΟʹܕΛ͚ͭΔ w int΍floatͷΑ͏ͳϓϦϛςΟϒܕ΍ɺ string˱char*͸҉໧తʹม׵͞ΕΔ w ߏ଄ମ΍഑ྻͷϝϯόͷchar*΁ͷ୅ೖ͸҉໧తʹ ม׵͞Εͳ͍౳ͷ੍໿΋͋Δ w

    surface()Ͱ͸ɺnode->surface͸ղ ੳݩͷจࣈྻͷઌ಄͔ΒϙΠϯλΛਐΊͨ ΋ͷͰɺޙΖʹ༨෼ͳ಺༰ΛؚΜͰ͍Δͷ Ͱඞཁͳ௕͚ͩ͞Λίϐʔ͍ͯ͠Δ ࣮ફ5JQT ߏ଄ମ͸ΫϥεͰϥοϓ
  18. w ϥοϓͨ͠ߏ଄ମΛഁغ͢Δͷ ͸1)1ΫϥεͷσετϥΫλͰ w 1)1͕ग़ͨࠒʹϦιʔεΛϥ οϓͨ͠ΫϥεͰߦ͍ͬͯͨͷͱ ಉ͡ख๏ ࣮ફ5JQT σετϥΫλΛ׆༻

  19. w mecab_t*ͱmecab_node_t* ͷΑ͏ʹ਌ࢠؔ܎ʹ͋ΔΦϒδΣ ΫτΛѻ͏ͱ͖ɺ਌͕ഁغ͞Ε ͨঢ়ଶͰࢠʹΞΫηε͢ΔͱΤϥ ʔ͕ൃੜ͢Δ w 1)1ϨϕϧͰ͸ٯʹʮࢠ͕਌Λ ॴ༗͢Δʯ͜ͱͰࢠ͕ੜ͖͍ͯΔ ݶΓ͸਌΋ੜ͖͍ͯΔΑ͏ʹ͢Δ

    ࣮ફ5JQT ΦϒδΣΫτͷϥΠϑλΠϜ
  20. ࣮ࡍʹΤϥʔΛى͜͢σϞ

  21. ͓ΘΓʹ

  22. QIQGGJNFDBC 50%0 w ''*ͷείʔϓػೳʹରԠ w ݱࡏ͸MeCab\TaggerのΠϯελϯεΛੜ੒͢Δ౓ʹ 
 ͦͦ͜͜େ͖͍ίʔυͷղੳͱMJCNFDBCͷಡΈࠐΈΛߦ͍ͬͯΔ w FFI::load()ͰείʔϓࢦఆˍFFI::scope()Ͱݺͼग़͢͜ͱͰޮ཰Խ

    w .F$BC-BUUJDFܥ"1*ͷ࣮૷ w ϥΠϒϥϦ࡞ऀͱͯ͠͸ͪΌΜͱػೳΛ໢ཏ͍ͨ͠
  23. ''* ࢖ͬͯΈͨײ૝ w ࢥͬͨΑΓ؆୯ʹ࢖͑ͨ w $ίʔυͷղੳ΍ܕม׵͕͔ͬ͠Γ࡞Γࠐ·Ε͍ͯΔ w Φʔφʔγοϓʹ͍ͭͯ΋ͪΌΜͱߟ͑ΒΕ͍ͯΔ w *%&ʹΑΔิ׬͕ޮ͔ͳ͍ͷ͸໘౗

    w 1)1ϚχϡΞϧͰ͸ڧΊͷܯࠂ͞Ε͍ͯΔ͕࣮ઓ౤ೖͯ͠Α͍ͱࢥ͏ w ग़དྷ߹͍ͷϥΠϒϥϦΛ࢖͏Ҏ֎ʹ΋ɺ1)1ʹෆ޲͖ͳߴ଎Խ͍ͨ͠ॲཧΛ3VTU΍ (P౳Ͱॻ͍ͯ$͔Β࢖͑ΔΑ͏ʹͯ͠ɺ''*ܦ༝Ͱݺͼग़͢ͷ͸ಛʹΞϦͩͱࢥ͏
  24. ''*͸໘ന͍ʂ ;FOEFYUFOTJPO"1*΋େม͚ͩͲ໘ന͍Ͱ͢