Quantcast
Channel: rana_kualuの記事 - Qiita
Viewing all 338 articles
Browse latest View live

2020/10/26までにAzure Database for MySQL/MariaDBのサーバ証明書を更新しないと死ぬ

$
0
0

Azure Database for MySQL/MariaDBを使用している全サービスについて、2020/10/26以降データベースに接続できなくなる可能性があります。
自分の環境を確認し、必要であればサーバ証明書を更新しましょう。

なお、以下はよくわかってないところを適当に解釈しているため、断言している部分にも誤りが含まれている可能性が多大にあります。
きっと誰かが訂正をプルリクしてくれるはず。

TL;DR

Azure Database for MySQL/MariaDBのサーバ証明書のルート証明書が変更される。

しないといけないこと

現在使っているBaltimoreCyberTrustRoot.crt.pemを、BaltimoreCyberTrustRoot.crt.pemDigiCertGlobalRootG2.crt.pemをくっつけたファイルに差し替える。

しないといけない場所

Azure Database for MySQL/MariaDBに手動でSSL接続しているクライアント側全て。
Azure Database for MySQL/MariaDB側ではない。

公式ドキュメント

Azure Database for MySQL のルート CA の変更について
Azure Database for MariaDB のルート CA の変更について

それぞれMySQLとMariaDB向けですが、中身はだいたい同じです。

記事を読むとわかりますが、何言ってるかわかりません。
私がわかっていないからというものもちろんありますが、それを抜きにしても文章からわかりにくさが溢れています。

Azure Databaseの確認

まずAzure管理画面から、Azure Databaseの『接続のセキュリティ』タブを開きます。
『SSL接続を強制する』にチェックが入っている場合は、以下の作業を行う必要があります。
チェックが入っていない場合は、SSL接続と非SSL接続の、両方の方法で接続することができます。
従ってその場合はクライアント側がどうなっているか調べて、SSL接続しているのであれば以下の作業を行う必要があります。

あれ?結局ここ調べる意味なし?

クライアントの確認

ここはクライアントの実装によって様々です。

接続にAzure Functionsの入出力バインドなどを使っている場合は、特に対応する必要はありません。
Azure側が自動的にアプデしてくれるからです。

VMや普通のサーバから接続している場合、もしくはFunctionsでも直接new PDOとかmysql.connector.connect()とかやっている場合は、調査を行いましょう。
接続まわりのソースにPDO::MYSQL_ATTR_SSL_CAとかssl_ca=xxとか書いてあったら、更新作業を行う必要があります。

する必要があるかどうかの厳密な判定

これは公式ドキュメントに書いてあるのですが、接続文字列のsslmodeverify-caもしくはverify-fullが入っていたら必要、となっています。
それ以外の文字、もしくはsslmodeがない場合は不要です。

sslmodeについて

サーバが渡してきたサーバ証明書を、クライアントがどこまで厳しくチェックするのかという設定です。
何故か詳しい解説がPostgreSQLのドキュメントくらいしか見当たらないんだけど。

sslmodeが無ければ、そもそもSSLではないので無関係。
sslmodeがあっても、値がallowpreferなら非SSL接続も行うため、SSL接続に失敗しても問題なし。
値がrequireであれば、SSL接続はするものの、クライアントはサーバ証明書をチェックしないので、証明書が正しくないことに気付かずSSL接続できるので問題なし。
値がverify-caverify-fullであれば、証明書が使えないことを正確に判定してエラーを出すため接続できない。

ということになってはいるのですが、まあわかりにくいですよね。
従って、SSLであればとりあえず作業するって方向でよいのではないかと思います。

作業内容

既存のBaltimoreCyberTrustRoot.crt.pemに相当するファイルをテキストエディタで開いて、下にDigiCertGlobalRootG2.crt.pemの中身をペーストします。

これだけでOKです。
いやー証明書って1ファイルにまとめて書いてもいいんですね。

これによって、今まで使っていたBaltimoreCyberTrustRootが使えなくなっても、その後はDigiCertGlobalRootG2で認証するので大丈夫、ということになります。

サンプル

これに差し替えるだけでOK。
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----

なお、Javaはこれではだめで、keytoolを使ってインポートする必要があるそうです。
よくわからないのでドキュメント読んでください。

なんで使えなくなるの?

よく 調べてないわからない。

SSL証明書は、証明書パスという仕組みで暗号化の安全性を保証しています。

Azure Databaseに使う証明書の安全性は、別の証明書Aが保証している。
証明書Aの安全性は、別の証明書Bが保証している。
証明書Bの安全性は、さらに別の証明書Cが保証している。
と繰り返していって、最終的にはルート証明書まで辿り着きます。
ルート証明書はブラウザやOSに最初から入っていて、無条件で安全であると見做されています。
従って、証明書パスにルート証明書が出てくれば、その証明書は安全であると判断するわけです。

Baltimore CyberTrust Rootもルート証明書のひとつです。
携帯電話にすら入っているほど有名な証明書で、有効期限も2025年までなのでまだ余裕があります。
ブラウザやOSには入ってますが、しかしPHPやらPythonやらJavaやらの言語には入っていないので、ルート証明書の判定用としてサーバに置いておく必要があるわけですね。

期限が先といっても、秘密鍵が漏洩したなどの理由で期限を待たずに強制的に失効することはままあります。
しかし、今回はルート証明書そのものが失効するわけではなさそうです。
そんなだったらもっと騒ぎになってそうですからね。

従って今回は、Azure Databaseに使っている証明書からBaltimore CyberTrust Rootへの証明書パスのどこかにある中間CA証明書が失効するものだと思われます。
ちゃんと調べればそこらへんもわかるはずですが、面倒なのでスルー。
まあおそらくは何かが漏れたとか認証局ごと信用を失ったとかだと思います。
証明書パスのどこかの証明書が失効すると、そこでパスが途切れてしまってルート証明書まで辿り着けなくなるので、その証明書は信用できない、となるわけです。

今回かわりに追加するDigiCert Global Root G2も同じくルート証明書で、こちらは2038年まで使えます。
同じルート証明書を使う証明書を発行すれば、差し替えも必要ないと思うのですが、何故ルート証明書まで変更するのかはよくわかりません。

まとめ

Azure Databaseを使っている人は、速やかに確認しましょう。

まあAzure Databaseは高いので、個人レベルで使ってる人はそんなに多くないと思いますが。
そのぶんデフォルトでレプリケーションやらバックアップやらが付いてきて高可用性を確保していたりと高性能なのですが、如何せん最低ラインが4k/月です。
スケールのこととか全く考えなくていいのは非常に楽なのですが、個人ユースでそんな限界に突き当たることなんて滅多にありませんからね。
もっと低スペックでも止まってもいいので1k/月とかのやっすーいプランもほしいところですね。


きみもハクトーバーフェストに参加しよう!

$
0
0

ハクトーバーフェスト オクトーバーフェスト 日本語訳 Hacktoberfest

10月といえばオクトーバーフェストです。
今年は色々あって大々的なお祭りって感じではありませんが、それでも新宿駅前でやってるのを先日見かけました。

まあ私は一人でお酒飲まないので行かないのですが。

そんなわけでこの業界にもオクトーバーフェストの波がやってきました。
2020/10/01から2020/10/31まで、Hacktoberfestというイベントをやっています。
今年はあのdev.to全面協力していて、ここからたくさん参加しているようです。
みなさんも是非参加してみましょう。

Get ready for Hacktoberfest

オープンソースをサポートして、限定Tシャツと植樹をゲットしよう。

Hacktoberfest presented by DigitalOcean

Event details

ハクトーバーフェストは、開発者、コードを学んでいる学生、イベントのホスト、大企業から中小企業まで、誰もが参加できるイベントです。
オープンソースの成長を助けし、コミュニティに積極的に貢献することができます。
あらゆるスキルレベル、あらゆるバックボーンの人に、このチャレンジに参加する権利があります。

・ハクトーバーフェストは全ての参加者のためのお祭りです。
・プルリクエストは、GitHub上でホストされているリポジトリ、プロジェクトに対して行います。
・期間は10月1日から10月31日です。

Rules

参稼報酬を獲得するには、10月1日から10月31日の間にログインし、有効なプルリクを4つ送る必要があります。
対象となるリポジトリは、Hacktoberfestに参加すると明示されているものだけではなく、GitHubでホストされている全ての公開リポジトリです。
もしプロジェクトのメンテナがあなたのプルリクをスパムとして処理したり、もしくはプロジェクトの規約に則ってない行動が見られた場合は、参加刺客を取り消されます。
そして今年は、チャレンジを成功させた先着7万名に賞品がプレゼントされます。

Tシャツや報酬を獲得する方法は、詳細を確認してください。

Global events

2020/10/06 Hacktoberfest Tuesdays: Americas
2020/10/08 Official DigitalOcean Hacktoberfest Celebration
2020/10/13 Hacktoberfest Tuesdays: Asia
2020/10/15 Official DigitalOcean Hacktoberfest Celebration
2020/10/20 Hacktoberfest Tuesdays: Israel
2020/10/27 Hacktoberfest Tuesdays: Europe

これは公式トップに載っていた代表例です。
全イベントは458個もあるみたいなので、いくらでも参加し放題です。
覗いてみてはいかがでしょう。

感想

参加方法は非常に簡単で、まずログインページからサインインし、あとは普通にプルリク出すだけです。

というか、もう半分終わっとるやんけ。

なに大丈夫、逆に考えるんだ、あと半分残ってると考えるんだ。
実際プルリク4本なんてオプソやってたら数日で埋まる量です。
一ヶ月に4回プルリクやってない奴なんておらんやろー

選択制、公平性、イノベーションを促進するアプリストアの10原則

$
0
0

最近アプリストアについて色々とごたごたがありましたが、マイクロソフトは2020/10/08に自身のアプリストアについてのスタンスを表明しました。

10 app store principles to promote choice, fairness and innovation

ソフトウェア開発者にとって、アプリストアは最も人気のあるデジタルプラットフォームの入口です。
我々や他の開発者たちは、時折一部のアプリストアについて疑問や懸念を表明してきました。
しかしながら、自分自身はどのようにあるべきか表明する必要があると認識しました。
そこで我々は、最も有名なプラットフォームであるWindows10と、Windows10のアプリストアであるMicrosoft Storeにおいて、選択制、公平性、イノベーションを促進する10の原則を採用します。
これはCoalition for App Fairness (CAF)のアイデアに基づいたものです。

1

開発者には、当社のアプリストアを通してWindows用アプリを配付するか否かを選択する自由があります。
Windowsが競合するアプリストアをブロックすることはありません。

2

コンテンツをあらかじめインストールするか、クラウドからストリーミングするかといった、開発者のビジネスモデルやサービスの配信方法などに基づいて、アプリをブロックすることはありません。

3

開発者がアプリ内で独自の決済ロジックを導入したことによって、アプリをブロックすることはありません。

4

当社の運用規則に定められているとおり、Windowsにおける相互運用性に関する情報を速やかに提供します。

5

全ての開発者は、セキュリティ・プライバシー・品質・コンテンツ・安全性などの客観的基準と要件を満たしているかぎり、当社のアプリストアにアクセスすることができます。

6

当社のアプリストアは、Windows上の他の競合アプリストアの兼ね合いを反映した適切な手数料を請求します。
また、開発者が販売したくないものを強制的に販売させることはありません。

7

当社のアプリストアは、適法であるかぎり、開発者とユーザが直接コミュニケートすることを妨げることはありません。

8

当社のアプリストアは、当社自身が発行するアプリを、他社のアプリと同じ基準で審査します。

9

マイクロソフトは、開発者の非公開情報やデータを、競合アプリを開発するために使用することはありません。

10

当社のアプリストアは、ルールとポリシーについて、またプロモーションやマーケティングの機会について透明性を保ち、一貫的に客観的に運用します。
変更については通知を行い、紛争を解決するために公正なプロセスを利用できるようにします。

我々は、技術やビジネス、規制などのために、これらの原則の追加や変更を随時行うことがあります。

How these principles will work

Windows10はオープンプラットフォームです。
他のデジタルプラットフォームとは異なり、開発者は自分のアプリをどのように配布するかを自由に選択することができます。
Microsoft Storeはその手段のひとつにすぎません。

Microsoft Storeから利用できるアプリは強力なプライバシー、セキュリティ、安全性を満たしていることを保証し、開発者が開発に集中できるようにツールやサービスを提供し、そしてユーザはアプリを容易に見つけることができることで、ユーザと開発者の共に大きなメリットをもたらすことができると信じています。

しかし、Windowsには他にも人気があり、競争力のある多くの選択肢が存在します。
SteamやEpicなどサードパーティ製のアプリストアが利用可能で、開発者に様々な価格のオプション、要件、機能を提供しています。
さらに開発者は、自分たちの思うままインターネット上で直接配布することすらも簡単にできます。

原則のうち最初の4つは、この選択の自由を守ること、それを可能にするWindwos10の競争と革新についてのものです。
Microsoft Storeを選んだ開発者には、他のストアを選んだ開発者と同じ客観的な基準による合理的で競争力のある料金を設定することができます。

残りの原則は、その原則を保証することを目的とします。
たとえば、アプリ開発者が望んでいないにもかかわらず、アプリ内課金を強制されることに不満を表明することがありました。
そこで原則6では、Microsoft Storeを選択した開発者は、アプリ内で何を販売するかを強制されず自由に決めることができることを保証します。

今後数か月にわたり、現在のMicrosoft Storeのルールやポリシーと、今回発表した原則についてのギャップを埋めるために必要な作業を行っていきます。

我々はXBOXコンソールも運営していますが、この原則はXBOXストアには適用しません。
ゲームコンソールは特定の用途に最適化された特殊な機器です。
熱狂的なファンが多数存在するとはいえ、PCや携帯電話よりはるかに小さい市場しかありません。
また、ゲーム機のビジネスモデルは、PCや携帯電話のエコシステムとは大きく異なっています。
ゲーム機メーカーは専用のハードウェアを開発するために多額の投資を行っていますが、コンソールを低価格で販売することで、開発者やパブリッシャーが利益を出せるモデルを構築しています。
このようにプラットフォームの重要度とビジネスモデルの根本的な違いから、ゲーム機のための正しい原則は別に確立する必要があります。

What's next?

我々は、ソフトウェア開発者とプラットフォーマーが公平に利益を得られる方法と、アプリストアが進むべき最善の進路について、オープンに話し合うことが重要だと考えています。
何十億人の消費者の日常生活においてアプリは重要な役割を果たし、何百万もの企業がデジタル経済を回す動力源になっています。
しかし、アプリ経済を加速させるイノベーションには、健全で活気のあるデジタルプラットフォームが必要です。
規制当局や政策担当者は、これらの問題を検討し、デジタルプラットフォームにおける競争とイノベーションを促進するための法改正を検討しています。
CAFの原則とその実施は、その現実的な例として役立つであろうと確信しています。
この原則をMicrosoft Storeに適用することは最初の一歩であり、今後のために開発者や多くのコミュニティからのフィードバックをお待ちしています。

感想

そもそもMicrosoft Storeってマイナーだよね。
Windowsをメインで使っている人でもMicrosoft Storeって何?って人は多いのではないでしょうか。

Windowsの場合、Amazonやら楽天やらヨドバシやらSteamやらその他多種多様な課金システムを使えるおかげで、あえてMicrosoft Storeを使おうって人はそんなに多くありません。
しかし、Microsoftがそれらのストアに対して制限を加えたなんて話は聞いたことがありません。
OS自体はオープンではなくとも、その上で動く課金システムには広く自由を認めているWindowsは、そういう意味でオープンです。
またAndroidについても、ほぼGoogle Playの独占とはいえ、他のアプリストアを使うことも一応は可能です。
たとえば手持ちのGalaxyにはGalaxy Storeがデフォルトで入っていました。
そういう意味で最も問題となるのは、他の選択肢を取ることが一切できないApple Storeということになるでしょう。
あと原則の8とか9とかはsharlockedの話ですね。
Microsoftはこんなことしないよ、という宣言です。
Microsoftの場合しますからね。

この原則をXBOXに導入しないのは、XBOXは所詮ゲーム機であり、インフラである電話とは立ち位置が異なるのでまあ妥当でしょう。
これが他に選択肢の存在しない独占レベルにまで普及したらまだわかりませんが、まあXBOXがそんなに売れるとは思えな…

ほぼ独占といえばSteamでも似たようなことで揉めていたところがありましたが、そこは結局別のアプリストアを立ち上げました。
別の解決策を取れるかどうか、市場の占有率がどうなっているか、そしてそれ以上に生活インフラであるかによって、この手の問題への解決策が変わりそうです。
小さいストアが奇妙な条件を設定したところで使わなければいいだけですが、それがインフラになっていたらそう簡単には変更できませんからね。
Apple Storeはそこらへんの見極めを誤ったという印象です。
今後Coalition for App Fairnessはどうなるでしょうかね。
なんとなく立ち消えになりそうな気がしないでもない。

あと心底どうでもいいんだけど、何度も原則って書いてるとどうしても人生最大の発見とかいう電波を思い出してしまう。

アルゴリズムのせいで面接に落ちた

$
0
0

Original article:https://dev.to/raulfdm/i-failed-an-interview-because-of-an-algorithm-3f9k

以下はRaul Melo ( Twitter / GitHub / dev.to / Medium / Webサイト ) による記事、I failed an interview because of an algorithmの日本語訳です。

I failed an interview because of an algorithm

開発者の皆さん、こんにちは。

この数週間、私はとある大企業の採用プロセスに参加していました。
それは非常に刺激的な経験で、採用過程についての多くの知見、コーディングの課題、そして面接のためにどのような準備をする必要があるかと、多くのことを学びました。

タイトルでわかるとおり、私は合格できませんでしたが、全ての段階を経験しました。
なので、これから初めて仕事に就こうとしている人、転職を考えているけど数年は面接をしていないという人たちにとって、参考になるかもしれません。

これから採用プロセスの全段について、感想を交えつつ詳細に説明していきますが、主に伝えたいことは、なぜ最後のパートで失敗したということです。
私の経験が、あなたの役に立つことを祈っています。

Stage 1: Getting an interview

欠員を埋めるために、社員にインセンティブを出して人を紹介してもらうことは、一般的な企業でごく普通に行われています。
(ネット内外で、できるだけ良い人脈を作った方がよい理由のひとつです)

私の友人が、彼の会社で働くことを勧めてくれました。
給料もよく、組織もしっかりしていて、とても働きやすい職場だから、来てみないかい?

私は自分のオンライン履歴書を多少調整する必要がありましたが、その準備はすぐに終わりました。

Stage 2: Human Resources (aka HR)

会社の人事担当が、私のことを知りたいと電話をかけてきました。

私の職歴やこれまでの人生でやってきたこと、特定の知識(React、テスト、Reduxなど)を持っているかどうか、そして今働いている会社について尋ねてきました。
正直なところ、これらの質問は非常に基礎的で些細なことばかりだったので、単に履歴書で嘘を言っていないかフィルタしているだけのように思われました。

私は全ての質問に自信をもって答えたし、担当者も電話の最後にポジティブな言葉をくれました。
そして次に、こんどは技術リーダーとチームマネージャと面接を行うことになりました。

Stage 3: The managers

翌週、私はマネージャとWebカメラ越しに1時間の面接を行いました。

彼らのビジネスは、私のソフトウェアスキルについて知ることでした。
次のような質問を受けました。

・今までのキャリアで最も誇りに思った瞬間は何ですか?
・今までに行った技術的決断の中で最も悪かったものは何ですか?
・敵対者とどのように立ち回りますか
・トップダウンの意思決定にどう立ち向かいますか
・紛糾した議論をどう収めますか

そしてこれらの質問について、私が実際に考えたり問題に対処していたと証明できるように、幾つかの状況を例示するように求めてきました。

自分のキャリアの中でよかった時のことと悪かった時のことを思い出すことになり、プロとして人として成長できたと感じられました。

面接を終了したとき、私はその結果にとても自身がありました。

数日後、人事から電話がありました。
マネージャは私のことを気に入り、そして私の受け答えはとてもよかったと教えてくれました。
唯一のフィードバックは、"受動的になりすぎていた"ということでした。
彼らは私のことをリーダーではなくフォロアーであるように認識していました。
私はもうすぐ30になりますが、正直なところ技術的な好みやコードの書き方についての無意味な議論を続けるエネルギーを失ってしまいました。
個人的な意見は持っていますし、どうしてそう考えているかを主張することは今でもできますが、でも話が個人的嗜好の押し付けになってくると、諦めて人の好きにさせるだけです。

私にとって、最高のJSフレームワークは何か、最高の状態管理ライブラリは何か、reduceを使うべきかmap+filterを使うべきか、Jestでitを使うべきかtestを使うべきか、などといった話題はもはやどうでもいいです。

私が気にするのは、問題解決に最適なソリューション、適切なネーミング、テスト、可能なかぎりシンプルな解決策、製品出荷、そして今月の給与額です。

かつては何が一番良いか、何が最もよくないか、など終わりのないバトルに明け暮れていました。
今でもそういった話に参加することはありますが、話が進まなくなったらただただ同意して先に進むようにしています。

とはいえ、それらを馬鹿にしているわけではありません。
悪い判断がなされてしまったと確信し、そしてそれを証明できるならば、それを防ぐために何処までも戦います。
会社の立場からすると、最も価値のある選択を行うために長い議論をすることも必要かもしれません。

Stage 4: the HR (again)

その後また人事から電話があり、前回マネージャに聞かれた質問について再び聞かれました。

私のソフトウェアスキルについて、自分自身でも確認してみたかったようです。
特に嘘をついたりはしていなかったので、同じ回答をできました。
また、どうして私がフォロアー的体質だとマネージャが感じたかの理由について得心したようでした。

次のステップは、二人の開発者が私のハードウェアスキルをテストし、QAマネージャがその審査をするということでした。

Stage 5 (latest): The devs

このステージが最難関だったので、ここについては詳細に語ろうと思います。
わからないことがあれば、疑問に答える幾つかの記事をお勧めします。

最初にメールで、JavaScript、CSS、テスト、ステート管理、React、そしてHTTPなどのトピックについて質問するという概要が来ましたが、具体的にどのような話になるのかはまだわかりませんでした。

面談は1時間30分の予定でしたが、10分遅れて始まりました。

チャットルームに参加すると、まずどのように進行するかについてプレゼンを受けました。
・私が現在何をしているかを知るために20分~
・技術的コンセプトについて回答と解説に30分
・コードチャレンジに30分

About me

まずは再び、私が今の仕事で何をしているかを説明しなければなりませんでしたが、これまでよりぐっと技術的な話でした。
もっとも、Webエコシステム全体を担当しているのは私ともう一人だけだったので、プロダクトがどのように構成されているかは概ね把握していました。
プラットフォームは何か、私の責任担当は何か、日々のタスクはどのようなものか、チームをどのようにハンドリングしているか、などについて詳細に話しました。
幾つかのトピックについては深く掘り下げて質問されることもありましたが、特に問題になることもなく終了しました。

Technical questions

ここから話は技術的でトリッキーなものになり始めました。
ここでは詳細な解決策にまで言及することは避け、質問に対する私の印象、そしてそれらを解説する記事へのリンクを付けておきます。

JavaScript questions

Can you explain the difference between var, let, and const?

var/let/constの違いを説明できますか?

油断のならない質問です。
最近JSを始めた人は特に。

多くの人はこう答えると思います。
『基本的に常にconstを使い、再割り当てが必要な場合にのみletを使う』

幸い、私はvarからlet/constへの移行を目の当たりにしていたので、これがスコープについてのものであることをはっきりと覚えています。

constを使っていても再割り当てが行われることを示すため、彼らはふたつ目の質問を投げかけてきました。

Var, let and const- what's the difference?

How can you freeze an object?

オブジェクトの再割り当てを禁止する方法は?

ES6の学習中にこれを起因とするバグに遭遇していたので、この概念を知っていました。
オブジェクトが何故突然変異しているかを調べた結果、Object.freezeに辿り着きました。

これはわかりやすい機能です。
オブジェクトをfreezeさせると、その後値を変更しようとしても変化することはありません。
ただしfreezeはオブジェクトの1段階目にのみ有効であって、入れ子の奥にあるオブジェクトや配列はfreezeしないことに注意しましょう。

const 📦, seal 🤐, freeze ❄️ & immutability 🤓 in JS

Can you explain what DOM is?

DOMとはなんですか?

何の頭文字かは忘れましたが(Documment Object Model)、一番簡単な質問だったと思います。

DOM Tutorial

Can you explain how events propagate in the DOM?

DOMのイベントバブリングについて説明してください。

この質問に答えることができたのは、Reactを使い始める前に自分でJSフレームワークを作った経験があったからです。
至る所で発生するイベントをキャプチャしたり、バブリングの仕組みを学ぶことができたよい経験でした。

Event Propagation in Three Parts!

What's the advantage of using a single event to capture events?

イベントのキャプチャをひとつにまとめることの利点は?

この質問については、正直よくわかりませんでした。

かつてバニラJSでフォームを作ったときに、個々のinput全てにonChangeイベントを設定するのではなく、formに設定して内部で処理を分岐するように実装したことがありましたが、どうしてそのようにしたのかは忘れてしまいました。

私の予想はパフォーマンスでした。

回答はまさにその通りで、またそのことのとてもよい例を教えてくれました。
何千ものレコードを持つテーブルがあったとして、全ての行にイベントを設定すると、DOMは何千ものイベントを管理しなければならなくなるため、確実にパフォーマンスの問題が発生するでしょう。

この記事の例が気に入りました。

Event Delegation - What is it and why should I care?

Do you know what the Request animation frame API is and why we would use that?

Request Animation Frame APIを知っていますか?どうしてこれを使った方がいいですか?

この5年間でRequest Animation Frame APIは一度か二度くらいしか使ったことがなかったので、どうしてこのようなAPIが存在するのかわかりませんでした。
そのため、アニメーションのパフォーマンスを上昇させるためではないかと推測しました。

そのとおりだと教えてくれました。

Creating animations in Javascript using requestAnimationFrame

CSS questions

Do you know about the different displays?

displayの違いについてわかりますか?

この質問は初耳でした。
各displayプロパティについて説明すればいいのか、それとも単に「はい、知っています」と答えればいいのかよくわかりませんでした。
とりあえずinlineinline-blockblockgridflexなどがありますと答えましたが、どうやらそれが彼らの求めていた答えのようでした。

CSS Display property

What's the difference between display inline and display inline-block?

inlineinline-blockの違いは何ですか?

これは覚えていませんでした。
inlineblockはCSSではよくある違いなので知っていましたが、inlineinline-blockの違いまでは覚えていませんでした。

面接官が説明してくれましたが、inline-blockは要素にmarginpaddingを定義できるのに対し、inlineにはできないということでした。

CSS Basics Layout Fundamentals: Block, Inline & Inline Block

How can I center something vertically?

どうやって中央に縦に並べますか?

他の似たようなトリッキーな質問が来るかもしれません。
なぜなら色々な方法があるからです。

私が知っているのはdisplay: flexを使って、justify-content: centeralign-items: centerで並べるというものでした。

そして、それで十分な答えでした。

How to Vertically Align Anything with CSS

HTTP questions

Can you tell us what methods are available in HTTP?

HTTPで利用できるメソッドを教えてください。

Nodeでバックエンドを扱っていたので、さほど難しくないと感じました。

・GET
・POST
・DELETE
・PUT
・PATCH

するとPUTとPATCHの違いについて聞かれ、そして頭を抱えました。
片方はデータ全体を新しい内容に置き換え、もう片方は送信された内容のみを更新するものだったと思うのですが、どっちがどっちかを覚えていませんでした。
正解は教えてもらいました。

さらにOPTIONSのような他のメソッドを知っているかも聞かれましたが、正直全然知りませんでした。
時々ネットワークモニタでOPTIONSの文字を見ることはありましたが、それが何なのかを気にしたことはありませんでした。

Difference Between Those HTTP Requests

How the HTTP status codes are divided?

HTTPステータスコードはどのように分けられていますか?

これはHTTPの基礎です。
APIを使うアプリを作るようになってから、この意味を調べてhttps status dogsを見つけていたので、それを暗記していました。
これは素晴らしい覚え方です。

The HTTP Status Codes You Need to Know

Technical Challenge

小テストのような問題を想定していたので、技術的課題にはかなりの覚悟で臨んでいました。

30分あればきっと解けるに違いない

ひとつのJSファイルと共にCode Sandboxへのリンクが送られてきました。

// index.js/*
We have lots of deployment dashboards where we have drop-down UI to select an application version to deploy. We want to ensure that software version numbers delivered to our UI from the back-end API are always ordered with the newest (highest) available version at the top.

Eg:
const input = [0.1.0, 3.2.1, 2.2.3, 0.1.1];
sortVersions(input) should return [3.2.1, 2.2.3, 0.1.1, 0.1.0];
*/constsortVersions=(unsortedVersions)=>{// code};exportdefaultsortVersions;

そして動作確認のテストファイルも。

// index.test.jsimportsortVersionsfrom'./index';it('should sort correctly numbered versions',()=>{constversions=['0.2.0','3.1.2','0.1.6','5.0.0'];constoutput=['5.0.0','3.1.2','0.2.0','0.1.6'];expect(sortVersions(versions)).toEqual(output);});// Other assertions

課題のルールとして、GoogleでJSのAPIについて検索することは許可されていますが、具体的な解法の検索は禁止でした。

最初の問題はとても簡単でした。
回答もシンプルです。

constsortVersions=(unsortedVersions)=>{// codereturnunsortedVersions.sort().reverse();};

あっさり合格です。

さらに二つ目のアサーションファイルが送られてきたのですが、私はここで詰まってしまいました。

// index.jsit('should sort correctly numbered versions with different lengths',()=>{constversions=['1.3.0.9','0.2.0','3.1.2','0.1.6','5.0.0','3.3.3.3','3.3.3.3.3','3.10','0.2.0',];constoutput=['5.0.0','3.10','3.3.3.3.3','3.3.3.3','3.1.2','1.3.0.9','0.2.0','0.2.0','0.1.6',];expect(sortVersions(versions)).toEqual(output);});

先ほどの私の回答では、答えはこうなってしまいます。

['5.0.0','3.3.3.3.3','3.3.3.3','3.10','3.1.2','1.3.0.9','0.2.0','0.2.0','0.1.6',];

何故そうなるかというと、単純な文字列比較を使っているからです。
アルファベット順では3.33.10より後になります。
しかし、セマンティックバージョニングでは3.3より3.10のほうが大きくなります。

ソート方法をいじくって、全てのバージョン文字列を最も長いバージョンと同じ形式に揃える方法を思いつきました。
正直この時点でだいぶ緊張していたのですが、その『単純な』解法を思いつくことができず焦ってしまいました。
面接官が解法のヒントを教えてくれたのですが、理解することができませんでした。
正確に教えてくれなかったからというわけではなく、様々なことを同時に考えすぎていたため頭が追いつかなかったのです。

全てのバージョンを同じ長さにするコードを書いているうちに、時間切れになってしまいました。

もっと時間があったらどのように解決するか聞かれたので、このように全てのバージョンを同じ長さにしてブロックごとに比較すると答えました。

面接のために時間をとってくれたことに例を言い、我々は通話をオフにしました。

もしこの問題に興味があるならば、StackOverflowを覗いてみるとよいでしょう。
この回答は全てのテストをパスしました。

After the test

正直、通話を切った時点で駄目だったと確信していました。

過去5年間でもっと難しい問題もたくさん解いてきたというのに、ただのソート問題程度にやられてしまいました。
私はいったいどうしてしまったのでしょうか?

しかし、それ以前の全てのステップはうまくいった、技術的な質問もだ、きっと挽回できる。
必死に自分を慰めようとしました。

The last HR Call

一週間の煩悶ののち、人事担当から電話がかかってきました。

「残念ですが、ここでおしまいです。」

悔しさを抑えきれませんでした。
その理由と改善点について尋ねました。

開発者はあなたのコミュニケーション能力やエネルギー、しすてほとんどの技術的質問に正確に答えたことをとても気に入っています。
しかし、最後の問題の方針がよくなかったと考えています。

頷くしかありません。

この決定に異を唱えることもできたかもしれませんが、既に裁定は下されたのです。
結果を変えることはできないでしょう。

電話を切った後5分ほど立ち竦み、感情を消化し、このプロセスの全てについて顧みることにしました。

Thoughts about hiring X our skills

あなたがその人生で面接担当になったことがあるかはわかりませんが、私はあります。
それは簡単なことではありませんでした。
採用プロセスは、一般的に非常に難しい問題です。

我々は候補者を透明性や正確性を最大限に保ちながら評価する基準やステップを定義しなければなりませんが、いまだに完璧な方法は存在しません。
人々は互いに異なる方法で考え、学び、問題を解決し、コミュニケートしています。
我々は全員に共通するガイドやフィルタで他者を評価しようとしています。

すなわち、誰かがあなたの期待する基準に合わなかったとすれば、それはその人がこの仕事に向いていなかったという印かもしれません。
しかし、それはその人に才能がないことを表すのでしょうか。

私は決してそう思いません。

私は開発者として初めて仕事をしたときに、似たようなコードチャレンジを行い、そして突破した記憶があります。

当時の私と今の私では何が違うのでしょう。
そのころ、私はFreecodeCampでアルゴリズムの問題を解く練習をしていました。

就職してからは、私は優秀な社員であることを証明してきましたし、面接で聞かれた難しいアルゴリズムは、プロダクトには全く関係ないものだったと断言できます。
何故ならば、難しい問題を解決するために、他者がどのように解決しているかを調べるために、Googleを使わなくてよかった時間はほとんど無かったからです。

解決すべき難問はいくつも横たわっていましたが、それらを全て短時間で、あるいは長時間で、時には人の力を借りて、時には独力で乗り越えてきました。
今の仕事を得るために、公開APIを使うReactアプリを作り、E2Eテストを行い、無限スクロールやページ移動アニメーションを作りこみ、アプリをホストし、ソリューションを紹介し、そして幾つかの問題を解決するためにペアプログラミングに取り組みました。

そしてそれらは、今はお金を稼ぐために日々行っていることです。

アルゴリズムを解けないということは、開発者に向いていないということなのでしょうか。

そんなことはありません。
ある条件で問題を解くことに失敗したというだけのことです。
そしてそれが、ある人にとって他者の才能を評価する基準だったというだけのことです。

ここで言いたいのは、私が採用されなかったことに文句を言いたいということではありません。
面接に失敗したことが即ちプロとして失敗したという意味 ではないということです。

Learnings

採用プロセスは深く自分のためになりました。

次の機会があれば、そのときはソフトウェアスキルの質問にも容易に答えられるように準備をして挑むことにします。
それにinlineinline-blockの違い、OPTIONSメソッドとはなにか、PUTPATCHの違いなどはもう忘れることはできないでしょう。

しかし最大の学びは、全てに対して備えなければならない、ということです。

ReactやVueやAngularを使ったアプリの実装をさせられるかもしれませんし、トリッキーなJSの問題を振られるかもしれません。
備えるために、手始めにCodewarsFreeCodeCamp Learn、そしてCodility等に一日数時間を消費し始めました。

また自分のWebサイトに新しい何らかを実装し、堅牢なフロントエンドアプリを実装するスキルをさらに磨いていくつもりです。

Conclusion

私の経験が、あなたが初めての仕事を得るために役立ち、採用プロセスに立ち向かう準備を行う心構えになることを願っています!

コメント欄

「だからこそ、多くの開発者がもっと現実的な採用プロセスを求めているのだ。10年コーディングしてるけどフィボナッチアルゴリズムを使ったことがないし、ググれば5分で答えがわかる。」
「実際にはほぼ使われてないような怪しげなソートアルゴリズムで評価するなんて役に立つものかね?」
「ドキュメントに書かれてることを質問する採用プロセスは下策。開発者は脳内にマニュアルを持ち歩く必要はない。」
「開発者が半日かけてやっていることは、Googleで調べることだ。」「マイナーなライブラリを使っていたら検索に全く引っかからず、自分でどうにかするか開発者に聞くしかなかったんだが。」「そんなこともあるかもしれないがレアケースだろう。」
「マイクロサービス、CI/CD、Docker等の台頭によって日々の業務は大きく様変わりしているのに、面接プロセスがその変化を見抜けていないことに困惑する。」
「理論計算機科学はWeb開発者にとって直接役に立つものではないかもしれないが、問題を解決するためのツールとして役立つので知識を維持しておく価値はある。」
「Raulが落とされた理由は次のどちらかでしょう。A:既にsortできない開発者がたくさんいるのでもういらなかった。B:Guru開発者しか欲しがらない会社だった。Bの会社はイノベーションに必要な"愚かな"質問をする開発者がいないので、最後には失敗するだろう。」
「採用は双方向だ。会社があなたを評価するのと同じくらい、あなたも会社を評価し、一緒に働けないと思ったら断るくらいでいいのだ。」
「Object.freezeやrequestAnimationFrameといった質問は、知っていることそれ自体より、知識の幅の広さを調べようとしたのではないかと思います。知っていれば便利だけど、毎日使うようなものではありません。」
「ドットで区切ってそれぞれ数値比較すればいいんじゃね。」「おそらくそれが期待された答えで、特別なアルゴリズムも不要だよね。」

「以下はIntl.collatorを使った答えです。」

constsortVersions=(unsortedVersions)=>{returnunsortedVersions.sort(newIntl.Collator('en',{numeric:true,sensitivity:'base'}).compare).reverse()}

「数値で比較すると2.1.0aが正しくならないよ。」

constsortVersions=(x,v=(s)=>s.match(/(\d+)|[a-z]/g).map(c=>c==~~c?String.fromCharCode(97+c):c))=>x.sort((a,b)=>v(b)<v(a)?1:-1)

コメント欄で自説を滔々と開陳する人が多くて困惑する。
最後のコーディング問題そのものには、多くの人が面接で有用ではないだろうとコメントしていました。

感想

このくらいのスキルの人ならいとも簡単に解けそうな課題に見えるのですが、やっぱりこういう場では緊張してしまって実力が出せないなんてこともよくあるのでしょう。

面接でコーディングさせることについては私も懐疑的です。
なんかちょっとしたところで数時間引っかかって、解けるときは一瞬で解けるなんてことはこの仕事ではよくあることですからね。
コーディングそのものではなく、考え方を評価する手法は大いにありだと思います。
ただ、その点でいうとこの人の回答はあまり評価できるかんじではない気がしますね。

Qiitaでもよく転職系のエントリが上がりますが、なんというか根本的に採用プロセスが異なりますね。
面接にエンジニアが出てきてコードを重視する海外式、基本的にエンジニアが出ることはない日本式。
向こうも向こうで決して採用プロセスに満足しているわけではなく、色々と文句も出ているみたいですが、しかしどちらのほうがより優れているかといえば、海外式のほうが多少はよさそうではあります。
とはいえ、だったら日本の採用も全て海外式にするべきかと言われたら絶対に嫌ですね。
そういう企業があってもいいとは思いますし、あるべきだとも思いますが、全てがそうなるべきという意見には反対です。
何しろ私だったら一次面接で落とされる自信がある。

隙あらば自分語り

隙あらばってほど語った記憶は特にないけど、せっかくなので誰かの役に立つかもしれないし、自分の就活の話でもしておきますね。

国立大学を中退してコンビニバイトでぷらぷらやっていたのですが、当時の彼女に「就職もしてない人とは付き合えません」と言われたので仕方なくハロワに行きました。

当時の知識はというとプログラム=ゲームを作れるとかのレベルで、サーバ?なにそれおいしいの?
システムエンジニアとネットワークエンジニアの区別すらついていません。
ぶっちゃけ完全素人です。
そもそもプログラマになりたいとか何かを作りたいとか考えていたわけでもなく、社員になれればなんでもよかったので、事前に学習すらしていませんでした。

ハロワというとブラック求人ばかりとかクオリティ低いとか散々な言われようをされることが多いように思いますが、それまで書いたこともなかった職務経歴書の書き方(ほぼ空白)とか、面接の練習(問題点を死ぬほど突っ込まれた)とか色々を全て無料で教えてもらって、だいぶ人間に近づけたような気がするので今でも感謝しています。

そんなわけで就職活動を始めてからプログラミングの勉強を始めようとしたわけですが、ポートフォリオどころか参考書すら買う前に受けた2社目において、そこの面接官が何故か社長で、しかも何故か社長に気に入られてしまって速攻で正社員就職が決まりました。
面接の内容も、この記事のような技術的なものではなく、ほとんど世間話みたいなかんじで、せっかく教えてもらった付け焼刃の面接練習も役に立ったのかどうか微妙なところです。
もっとも技術的な話を振られたら間違いなく即死していたので、日本式採用プロセスには全面的に感謝しかありません。

まともに学習する前に採用されてしまったという結果でした。
そして現在もその会社で働いているので、実は転職経験もありません。
これで会社がアレだったら社畜乙ですが、ボナースは出るし有給も使い切ってるしここ数年は時間外平均10時間以下と、この業界にしては非常にゆるい環境だと思われるので、転出する気もあんまり起きないというか。
そのぶん額面はそこまでですが、でも激務だけど倍額出すぞと言われても今の方を選びますね。
10倍だったら悩むかも。
本当は今のままで倍額が、いや何もせずに10倍が一番いいんですけど。

せっかく思い返したのだけれど、誰の役にも立たないので書き起こす意味が全くなかったな自分語り。

Composer2.0ついにリリース!

$
0
0

Original article:https://blog.packagist.com/composer-2-0-is-now-available/

もはやPHPには欠かせないパッケージマネージャであるComposerですが、2020/10/24にComposer2.0.0がリリースされました。
2012年のリリース以来初めてのメジャーバージョンアップということで、多くの改善や新機能が盛り込まれており、そして互換のない変更点もわずかに存在します。
以下は公式でもアナウンスされている、Jordi Boggianoによる紹介記事Composer 2.0 is now available!の日本語訳です。

Composer 2.0 is now available!

1/ What's new?

何が新しくなったの?

変更点や改善点は非常に多岐にわたるので、全てを知りたい場合は変更履歴を確認してください。
ここではいくつかの重要なポイントについて解説します。

Performance improvements

Composerとpackagist.org間の通信で使用されるプロトコルや依存関係の解消などについて、依存評価の最適化、Curlの並行ダウンロードなどを用いて、全面的に改修を行いました。
これにより、速度とメモリ使用量の両方において大幅な改善を行うことができました。
実際にどのくらいになるかはユースケースによりますが、幾つかのプロジェクトでは50%以上の改善がみられました。
きっとComposer2を初めて試した時には驚くことでしょう。

また、require/removeや一部分だけの変更については、メタデータを変更されたところだけ取ってくるようにしたため、非常に高速化しています。

01.png
ext-curlを有効活用したComposer2は、初回インストール速度が6割も改善している。

Architectural changes and determinism

依存関係の解決を行う方法をリファクタリングしました。
vendorディレクトリの現在のローカルの状態が、updateに影響しないようになりました。

installはupdateが終わった後で実行されます。
これにより、全てのネットワークを使う動作は最初に実行されるようになりました。
さらに、これらは可能であれば同時に実行されます。
これにより、installの途中でネットワークエラーが発生した場合でも、中途半端に壊れたvendorディレクトリが残らないようになります。

Runtime features

プラットフォームチェックを追加しました。
vendor/autoload.phpが呼ばれた際、現在のPHPバージョンやエクステンションが対応したバージョンであるかをチェックし、一致していなければエラーにします。
これはデフォルトで有効になっています。

新たにComposer\InstalledVersionsクラスが追加されました。
全てのプロジェクトでオートロードされ、現在の環境に入っているパッケージおよびバージョンを確認することができるようになります。
詳細はドキュメントを参照してください。

あなたがこれらに依存したコードを書きたいのであれば、composer.json"composer-runtime-api": "^2.0"と記述してください。
これはComposerが提供する仮想パッケージで、Composer 2.xからの対応となります。

Error reporting improvements

常に何もかもがうまくいくとは限らないため、依存関係が解決できない場合に表示されるエラー報告の内容を改善しました。
失敗する理由はいくらでも存在するのでここで具体例を示すことはしませんが、メッセージは簡潔に、明確になり、また繰り返しが少なくなったことに気が付くと思います。

Partial updates with temporary constraints

一時的に何かをテストしたり、バグフィックスを待ったりするために、特定のパッケージを特定のバージョンにアップグレード・ダウングレードしたくなる場合があるでしょう。
たとえばcomposer update vendor/package:1.0.*とか1.0.12などと記述することで、該当のvendor/packageのみをこの制約にマッチするバージョンにアップデートすることができます。
このときにcomposer.jsonが更新されることはなく、ロックファイルが期限切れになったりすることもありません。

制約を付けたうえで依存関係を完全に更新したい場合は、update --with vendor/package:1.0.*とすることで、追加制約を保ちつつ更新することができます。

2/ How easy is it to upgrade?

アップグレードは簡単ですか?

我々の目標は、全てのComposerユーザーが迅速かつスムーズにComposerをアップグレードできるようにすることです。
アップグレードの恩恵は大きいので、皆に体験してもらいたいと思っています。
そのために、幾つかの対応を行いました。

・Composer 2.0は、1.x同様PHP5.3以降をサポートしている
・composer.lockは互換性があり、2.0へのアップグレードおよび1.xへのダウングレードが可能
・ほとんどのコマンドや引数に変更はなく、既存コマンドのほとんどはComposer 2.0でも使用可能

Composer1.xでcomposer self-updateを実行すると、新しいバージョンの安定版Composerが利用可能であることを通知します。
composer self-update --2を実行することで実際にアップグレードすることができます。

何らかの問題が発生した場合は、composer self-update --1ですぐに元に戻すことができます。
これによって、誰もが新バージョンをとりあえず試してみることができるでしょう。

インストーラスクリプトを使用してComposerを自動アップデートしている場合は、引数に--1を加えることで引き続きComposer1.xを使い続けることができます。
ただし、Composer1.xは今後長くメンテナンスされ続けるわけではないので、いずれはアップグレードすることをお勧めします。

3/ Backwards compatibility breaks?

ここでは、アップグレード時にトラブルが発生しやすい作業について紹介します。

Plugins

おそらく、最も多くの人にとって最大の問題になる部分だと思われます。
プラグインはComposer2をサポートするために更新されなければなりませんが、中にはまだその準備ができていないものも存在するでしょう。
Composer2はそのようなプラグインにはサポートされていない旨の警告を出したり、あるいはインストールに失敗するので、深く考えずにとりあえず試してみて様子を見てみるのが早いでしょう。

platform-check feature

新機能であるプラットフォームチェック機能は、ランタイムのPHPバージョンと、使用している拡張機能が依存しているバージョンが合っているかどうかをComposerがチェックします。
対象外だった場合はオートローダはエラーを出して停止します。
本番環境へのデプロイ時に問題が発生しないようにするには、ビルドプロセスの一部としてcomposer check-platform-reqs --no-devを実行するとよいでしょう。

Repository priority

優先順位の高いリポジトリにパッケージが存在する場合、優先順位の低いリポジトリにあるパッケージは完全に無視されるようになりました。
Composer2を使っていてパッケージが見つからない問題に遭遇した場合は、優先順位のマニュアルを参照してください。

Invalid PSR-0 / PSR-4 configurations

PSR-0 / PSR-4として正しくない形式のオートロードは、Composer1.10で警告が発生するようになり、Composer2ではオートロードされなくなりました。
大抵の場合、これらの警告はオートロードを意図していないクラスに対して発生するものなので、実質的な問題は発生しないと思われますが、アップグレード前に警告を一掃しておいた方が無難でしょう。

もっと詳しく知りたい場合は、UPGRADEのうち、自分が対象となっているセクションを読むことをお勧めします。

4/ What's next?

Comoposer2.0に全てを注ぎ込んだため、今のところ次のロードマップはありません。

重要なこととしてひとつ、今後サポートするPHPバージョンについて説明したいと思います。

上記で述べたように、Composer 2.0はPHP5.3をサポートしていますが、これは時代遅れのバージョンであり、このためにコードのメンテナンスが非常に困難になっています。
全てのComposerユーザがComposer 2.0にアップグレードできるように対応しましたが、今後のマイナーバージョンアップによって、EOLとなったPHPバージョンのサポートを打ち切る予定です。

Composer 2.1では、最終的に含まれる機能によってはPHP5.3のサポートが継続されるかもしれません。
しかし、Composer 2.2ではPHP7.1.3以前のバージョンのサポートは廃止される予定です。
我々の統計によると、90%以上のComposerユーザは引き続きComposerを使用可能です。
ただし、PHPのバージョンを上げることが困難なユーザのために、重大なバグ・セキュリティフィックスは当面は2.0.xにも提供していく予定です。

Composer 1.xについては、遠からずEOLとなります。
今後もクリティカルなものについては修正を提供する予定ですが、速やかに2.xに移行することをお勧めします。

最後に、リリースのために尽力してくれた皆様に感謝します。
Composer2.0には、28人から1100以上のコミット、150以上のissueとプルリクがありました。
そしてテストやプルリクのレビューを行ってくれた人にも感謝します。
最初のコミットから約2年、たいへんな努力の積み重ねがありました。

また本プロジェクトに資金と時間を提供してくれたPrivate Packagistにも感謝します。
皆様がComposerを使ってもらえることを心から願っています。

感想

yarnpnpmもその他多くのライブラリもだけどさ、どうして真っ先にインストール速度とかいうどうでもいいところを持ってくるんだろう。

ほぼ全ての開発者は開発環境構築マニアではないので、インストールなんて最初の一回やったらそれで終わりです。
PHPの場合は、コンパイル言語みたいにファイルを更新するたびにビルドしたりする必要もないのでなおさらです。
さらにComposerコマンドは、make等と違ってそもそもたいして時間がかかりません。
それにどうせコマンド入力した後はコーヒーを飲んでるだけなので、90秒が40秒に縮まったとか言われてもコーヒーを飲む時間が減るだけです。

インストール速度が50%アップするより、毎回の実行速度が1%アップした方がよっぽど嬉しいってものです。
なお実際試してみたところでは、実行速度は早くなっているのか遅くなっているのかわかりませんでした。
ロジックやDBアクセスに比べたら誤差みたいなものなので、いずれにせよ隙間に消える程度の速度差しかないようです。

しかし、なんといっても素晴らしいのが、コマンドひとつで簡単にアップグレード/ダウングレードできる機能です。
動くかどうかわからないからアップデートに躊躇する、なんてときにとりあえず試してみることができるのは非常に便利です。

またremoveのドライランやオフラインインストールなど、ここには書かれていない大量の機能も追加されているようです。
色々研究してみるのも楽しいかもしれません。

総合的には、とりあえずアップグレードして問題が発生しないかぎりそのまま運用する、で間違いないでしょう。

アップグレードしてみた

手元のローカルXAMPPで試してみたところでは、何一つ抵抗もなくアップグレード・ダウングレードすることができました。
コマンドも僅か数秒で実行完了したため、コーヒーを入れる暇すらありません。

プラグインも入れてないし、あまり変なライブラリも使ってないからというのもあるかもしれませんが、適当に動かしてみたところでは、特に影響を受けるアプリケーションもなさそうでした。
普通の環境では即Composer2.0にしてしまって全く問題なさそうです。

PHPの実行速度については、上記のとおりよくわかりませんでした。
むしろ0.001秒くらい遅くなったような気がするのですが、もしかしたら気のせいかもしれません。

8進数も基数表示を明記したい

$
0
0

PHPの数値リテラルは、いくつかの基数をサポートしています。

全部16
$a=16;// 10進数$a=0x10;// 16進数$a=0b00010000;// 2進数$a=020;// 8進数

8進数だけおかしくない?
ということでExplicit octal integer literal notationというRFCが提出されました。

Explicit octal integer literal notation

Introduction

PHPの8進数リテラル表記は、"016" == 016がfalseになるなどよくわからない結果になることがあります。
これは016が8進数であり、10進数でいう14になるからです。

この表記は、Java、C、C#、Golang、Haskellその他諸々の言語と同じ規則であり、たしかに確立された文法ではあります。
一方PythonJavaScriptRust0o表記のみをサポートしています。

PHPのoctdecbase_convert関数は、実はしれっと0o表記をサポートしていたりします。

Proposal

16進数の0x、2進数の0bと同じように、8進数リテラルを表す接頭辞0oをサポートします。

0o16===14;// true0o123===83;// true016===0o16;// true

Behaviour of numeric strings

PHP7.0では、文字列での基数表記はサポートされていません
数値型文字列における基数サポートは、複雑で混乱を招くため却下されました。

However supporting octal numbers is not possible, because handling the string '0123' as the number 83 would be highly unexpected for end users of an application.
8進数のサポートは不可能です。
なぜなら文字列'0123'を数値83と解釈することは、ユーザにとって全く予期せぬ結果になります。

従ってこのRFCも、文字列に対しては何の影響も及ぼしません。
'0o16'は今後もただの文字列です。

Backward Incompatible Changes

互換性のない変更はありません。

Proposed PHP Version(s)

PHP8.x

RFC Impact

To Existing Extensions

GMPエクステンションは8進数表記への対応が必要。
FILTER_VALIDATE_INTフラグのFILTER_FLAG_ALLOW_OCTALは対応が必要。

To Opcache

特になし。

Unaffected PHP Functionality

現在の、暗黙の8進数表記の動作に変更はありません。

Future Scope

・いずれ暗黙の8進数表記を非対応にする。
・数値型文字列において進数表記をサポートする。

Patches and Tests

GitHubには既にパッチが上がっています。

感想

えっマジかよ。
マジだった

var_dump(octdec('020'));// 16var_dump(octdec('0o20'));// 16var_dump(base_convert('020',8,10));// "16"var_dump(base_convert('0o20',8,10));// "16"

マニュアルにもユーザノートにも一切書かれていない超絶秘密機能が隠されていたとはびっくりだよ。
こういうのって、探せば他にもあるかもしれませんね。

さて、このRFCはまだ提出されただけです。
今後受理されるか却下されるかは、投票を待たなければいけません。
しかし特に反対するような理由もないだろうし、さらにSara GolemonNikitaの二人が早々と賛成しているので、まず間違いなく通るでしょう。

そしてそんなに重たい内容でもなさそうなので、おそらくPHP8.1あたりでさくっと導入されると思います。
今後は以下のようにわかりやすく表記できるようになることでしょう。

全部16
$a=16;// 10進数$a=0x10;// 16進数$a=0b00010000;// 2進数$a=0o20;// 8進数

0とoがわかりにくいな。

アロー関数で複数行書けるようにしたいよねっていうプルリク

$
0
0

PHP7.4で導入された便利機能アロー関数、みんな使ってますか?
私はあんまり。

$x=1;$fn=fn($y)=>$x+$y;$fn(1);// 2$fn(10);// 11

やはり1文しか書けないのと括弧で括れないので微妙に使い辛いんですよね。
ちょっとした確認とかにぱっと書けるのはいいのですが、1文ではあまり本格的な関数を書くことができません。
それなら普通に関数書くわってなりがちです。

ということでなんか{}で括って複数行書けるプルリクが来ていました。
提出者のNuno MaduroLaravel ZeroとかPestとか作っていて実績がある人です。
またプルリク自体の評価や注目度もとても高いです。
01.png

Adds support to multi-line arrow functions

みんなも知ってのとおり、PHP7.4でアロー関数が導入されました。
そしてこのプルリクエストでは、アロー関数に複数行の記述を許可します。
例を見てみましょう。

$users=[/** */];$guestsIds=[/** */];$repository=/** */;$guests=array_filter($users,fn($user){$guest=$repository->findByUserId($user->id);return$guest!==null&&in_array($guest->id,$guestsIds);});

このプルリクはPHP8.1での導入を目指していて、近日中にRFCを立てる予定です。

この機能の利点は、以下のように書くことができることです。

-$values = array_filter($values, function ($value) use ($first, $second, $third, $four) {
+$values = array_filter($values, fn ($value) {

・複数行アロー関数は、外部スコープの変数値を直接参照できるのでuseキーワードが必要ありません。
・それに、fn (/** */) {は大抵function (/** */) use (/** */) {よりシンプルです。

PHPコアへのプルリクは初めてなので、なにか改善すべき点があったら教えてください👍🏻

テストコード

$foo=fn(){};var_dump($foo());// null$foo=fn()=>1;var_dump($foo());// 1$foo=fn(){return2;};var_dump($foo());// 2$foo=fn($x)=>$x;var_dump($foo(3));// 3$foo=fn($x){return$x;};var_dump($foo(4));// 4$foo=fn($x,$y)=>$x+$y;var_dump($foo(4,1));// 5$foo=fn($x,$y){return$x+$y;};var_dump($foo(5,1));// 6$var=7;$foo=fn()=>$var;var_dump($foo());// 7$var=8;$foo=fn(){return$var;};var_dump($foo());// 8$foo=fn($var)=>$var;var_dump($foo(9));// 9$foo=fn($var){return$var;};var_dump($foo(10));// 10$var=11;$foo=fn()=>++$var;var_dump($var);// 11var_dump($foo());// 12var_dump($var);// 11$var=13;$foo=fn(){return++$var;};var_dump($var);// 13var_dump($foo());// 14var_dump($var);// 13$var=14;var_dump((fn()=>fn()=>$var)()());// 14$var=15;var_dump((fn()=>function()use($var){return$var;})()());// 15$var=16;var_dump((fn(){returnfn(){return$var;};})()());// 16var_dump((fn(){returnfn(){};})()());// null

これぞ求めていたアロー関数ってかんじですね。
最後のような使い方はやめてくれよって思いますが。

レビュー

いつものNikita
もうちょっと変数キャプチャを考える必要があります。
以下では外部の$xをバインドする必要はありません。

$x=1;$fn=fn(){$x=2;return$x;};

他にも幾つか疑問や懸念が来ています。

気になる構文

PHPでは素の{}にスコープがないんですよね。

$x=1;{$x++;}var_dump($x);// 2

ここにアロー関数が並ぶとこうなります。

$x=1;{$x++;}var_dump($x);// 2$x=1;(fn()=>{$x++;})();var_dump($x);// 1

どうなんだろう。

まあ、現時点で既にこんなだから、今さら気にすることでもないか。

$x=1;(fn()=>$x++)();var_dump($x);

感想

近日中に作ると言っておきながらRFCはまだ見当たりません。
またRFCやメーリングリストでは、構文や変数キャプチャ周りについて、色々と議論が発生しているようです。

とはいえ評価も高いし総論反対もほとんどいないようなので、PHP8.1か、まあ遅くても8.2あたりで入るのではないかなとは思います。
これで本格的にアロー関数を導入できそうですね。

初心者のためのWeb開発講座 レッスン01 プログラミング言語と開発ツール入門

$
0
0

MicrosoftがWeb-Dev-For-Beginnersという、Web開発初心者向けの講座を公開しています。
全24章からなる大作のレッスン講座となっています。

以下はそのうち最初の第一章、Introduction to Programming Languages and Tools of the Tradeの日本語訳です。

プログラミング言語と開発ツール入門

このレッスンでは、まずプログラミング言語の基礎を学びます。
ここで取り上げた特徴は、最新のプログラミング言語のほとんどに当てはまります。
次にツールセクションでは、開発者にとって有用なソフトウェアを紹介します。

Intro Programming

Sketchnote by Tomomi Imura

事前クイズ

・コードを書かなくてもプログラムを作ることはできる?

はい / いいえ

・低レベル言語がポピュラーな分野はどこですか?

Webサイト / ハードウェア / ゲームソフト

・Web開発者と最も関連性の高いツールはどれでしょう?

Raspberry Piのようなハードウェア / ブラウザ開発者ツール / OSドキュメント

Introduction

この講座には以下が含まれています。

  • プログラミングとは何か?
  • プログラミング言語の種類
  • プログラムの基本要素
  • 開発ツール

プログラミングとは何か?

プログラミング(コーディングとも表されます)とは、コンピュータやモバイル機器などのデバイスに対して、命令を出すことです。
命令はプログラミング言語で書かれており、そしてデバイスはその命令を解釈して実行します。
この命令は色々な名称で呼ばれることがありますが、プログラムコンピュータプログラムアプリケーション(アプリ)実行可能ファイル、などが一般的に使われています。

プログラムとは、コードで書かれている何かです。
Webサイトも、ゲームも、スマホアプリも、全てがプログラムです。
コードを書かずにプログラムを作ることも可能ですが、作り上げたロジックは実際にはコードで書かれていて、実際にデバイスが解釈するのはコードです。
プログラムはコードを実行し、デバイスに命令を出します。
あなたが今このレッスンを読んでいるということは、文字を画面に表示するというプログラムをデバイスが実行しているということです。

✅ ちょっと調べてみましょう:世界初のコンピュータプログラマは誰でしょうか?

プログラミング言語

プログラミング言語の主な目的は、開発者がデバイスに対して命令を送信する手助けをすることです。
デバイスはバイナリ(要するに0と1)しか理解することができず、そしてほとんどの開発者にとってバイナリはあまり効率的な命令手段ではありません。
プログラミング言語は、人間とコンピュータがコミュニケーションを取るための手段なのです。

世の中には様々な目的のために様々なプログラミング言語が存在しています。
たとえばJavaScriptは主にWebアプリケーションのために、Bashは主にOSとの対話のために使われます。

低レベル言語とは、デバイスが命令を解釈するために必要なステップ数が、高レベル言語より少ない言語のことです。
高レベル言語が人気であるのは、その読みやすさとサポート能力によるものです。
JavaScriptは高レベル言語とされています。

次のコードは、高レベル言語であるJavaScriptと、低レベル言語であるARMアセンブリの違いを表したものです。

letnumber=10letn1=0,n2=1,nextTerm;for(leti=1;i<=number;i++){console.log(n1);nextTerm=n1+n2;n1=n2;n2=nextTerm;}
areaascen,code,readonlyentrycode32adrr0,thumb+1bxr0code16thumbmovr0,#00subr0,r0,#01movr1,#01movr4,#10ldrr2,=0x40000000backaddr0,r1strr0,[r2]addr2,#04movr3,r0movr0,r1movr1,r3subr4,#01cmpr4,#00bnebackend

信じられないかもしれませんが、両者は同じ処理をしています。
いずれもフィボナッチ数を順番に10個出力します。

フィボナッチ数とは、各数がその手前の二つの値の和である値の集合です。

プログラムの基本要素

プログラムにおいてひとつの命令はと呼ばれ、文は通常は改行などの区切り文字で分かたれます。
プログラムの区切り文字は言語によって異なります。

多くのプログラムは、ユーザや他から来た入力データによって出力が変わります。
データによってプログラムの動作を変えるため、プログラミング言語にはデータを一時的に保存しておく方法が用意されています。
そのデータは変数と呼ばれています。
変数とは、デバイス内のメモリにデータを保存する文のことです。
プログラムにおける変数は数学における変数と似ていて、変数には固有の名称があり、その値は処理の経過に伴って変化することがあります。

プログラムには、実行されない文が現れることがあります。
これは、そうなるように開発者が設計して制御されたものであるか、予期せぬエラーが発生したかのいずれかです。
アプリケーションの制御は、堅牢で信頼性の高いプログラムを書くために必要なことです。
制御は、何らかの条件が満たされたことによって発生することが一般的です。
最近のプログラミング言語には、実行される文を制御するためにif...elseのような文が存在します。

✅ これら文については次のレッスンで詳しく学びます。

開発ツール

Tools of the Trade

このセクションでは、プロの開発者としての道を歩き始めるときに役立つであろうソフトウェアについて紹介します。

開発環境とは、開発者がソフトウェアを作成する際に頻繁に使用するツールや機能のセットのことです。
開発環境は、開発者が特定のニーズに合わせてカスタマイズしたり、優先順位を変更したり、異なるプログラミング言語を使用したりといった理由で次々と変わっていくこともあります。
開発環境は、それを使用する開発者の数と同じくらい千差万別です。

エディタ

ソフトウェア開発において最も重要なツールのひとつが、エディタです。
エディタはコードを書く場所であり、時にはコードを実行する場所であることもあります。

開発者がエディタを使う理由は、それ以外にも多々あります。

  • デバッグ
    コードを1行1行ステップ実行することで、バグやエラーを発見しやすくします。
    デバッグ機能を備えたエディタや、特定のプログラミング言語用にカスタマイズすることができるエディタも存在します。

  • シンタックスハイライト
    コードに色や書式を設定することで、コードを読みやすくします。
    多くのエディタはシンタックスハイライトをカスタマイズすることもできます。

  • 拡張機能
    デフォルトでは含まれない、一部の開発者向けに特化された拡張機能を追加することができます。
    例えば、コードをドキュメント化してどのように動作するかを確認したいユーザがいて、タイプミスのチェックのためにスペルチェックを行いたいユーザがいて、各自が自分のほしい拡張機能をインストールすることができます。
    ほとんどの拡張機能は特定のエディタでのみ動作するもので、そしてほとんどのエディタは拡張機能を検索する方法を用意しています。

  • カスタマイズ
    ほとんどのエディタは幅広いカスタマイズが可能で、開発者は自分のニーズに合わせた開発環境を作ることができます。
    さらに多くのエディタでは、開発者が自分で拡張機能を作ることも可能です。

有名なエディタとWeb開発向けのエクステンション

ブラウザ

もうひとつの重要なツールはブラウザです。
Web開発者は、自分のコードがWeb上でどのように実行されるかを確認するため、そしてHTML要素を視覚的に確認するためにブラウザを必要とします。

多くのブラウザには開発者ツールが付属しており、アプリケーションの動作を収集・分析するために便利な機能や情報があります。
たとえば開発者ツールを使って、Webページにエラーがあった場合に、いつどこでエラーが発生したかを把握することができます。

有名なブラウザ

コマンドラインツール

開発者の中には、日常の作業をGUIで行うことを好まず、コマンドラインに多くを頼る人もいます。
コードの開発には多量のタイピングが必要となるため、マウスを使うためにキーボードから手を外すことで作業の流れを中断されることを避け、キーボードショートカットを駆使して複数のファイルを操作したり複数のツールを併用したりします。

多くのタスクはマウスだけでも実行可能です。
しかし、コマンドラインの利点のひとつが、マウスとキーボードで行ったり来たりせずにキーボードだけで作業を完結できるというものです。
またコマンドラインのもうひとつの利点が、カスタム設定を登録しておくことが可能ということです。
さらにマシンを新調したときに設定を移動することもできます。

開発環境は個人個人によって非常に異なるため、コマンドラインの使用を避ける人もいれば、完全にコマンドラインだけしか使わない人もいます。
両方とも使う人も多いでしょう。

有名なコマンドラインオプション

コマンドラインオプションは、OSによって異なります。

💻はOSにプリインストールされているものです。

Windows

MacOS

Linux

有名なコマンドラインツール

ドキュメント

何か新しいことを学びたいと思ったとき、その使い方を学ぶためには大抵ドキュメントに頼ることになるでしょう。
開発者は、ツールや言語を適切に使用する方法を学んだり、その仕組みについて深く調べる場合、まずはドキュメントを参照します。

Web開発者向けの有名なドキュメント

✅ Web開発者の開発環境の基礎を理解したところで、Webデザイナーの開発環境との違いを見てみましょう。


🚀 チャレンジ

いくつかのプログラミング言語について比較してみましょう。
JavaScriptとJavaの特徴は?
COBOLとGoについては?

事後テスト

・Webサイトを作るときに最もよく使われるプログラミング言語はどれでしょう?

機械語 / JavaScript / Bash

・開発環境は開発者ごとに異なる?

はい / いいえ

・バグだらけのコードを修正するため、開発者は何をしますか?

シンタックスハイライト / デバッグ / コードフォーマット

レビュー & 自習

プログラマーが利用できる様々な言語について、少しだけかじってみましょう。
ひとつの言語で1行書いて実行したら、次は別のふたつの言語で同じことをやってみてください。
なにかわかりましたか?

感想

初心者向け講座の最初のレッスンだけあって、一切コードは出てこず紹介だけの内容です。
本当に初めての人向けの講座ですね。
次のレッスンからはいよいよJavaScriptか、と思えば先にGitHubの使い方アクセシビリティの話があって、その後ようやくJavaScriptというなかなか変わった構成になっています。

そんなペースで大丈夫か?と思えば後半は色々なプロジェクトを作ったりしています。
全24レッスンを踏破したころには、きっといっぱしのWeb開発者になっていることでしょう。


PHP8.0がリリースされたので新機能全部やる

$
0
0

2020/11/26にPHP8.0.0がリリースされました

ということで、UPGRADINGに載っている機能や変更点をだいたい全部見て回ることにします。

Backward Incompatible Changes

後方互換性のない変更。
なお、ここで削除される機能の多くは何年も前から公知されています

PHPコア

match is now a reserved keyword.

matchが予約語になりました。
match構文の導入に伴う措置です。

functionmatch(){}// PHP8.0Parseerror:syntaxerror,unexpectedtoken"match",expecting"("// PHP7.4エラーは起こらない

Assertion failures now throw by default.

assertのデフォルト動作が例外になりました。

assert(false);// PHP8.0Fatalerror:UncaughtAssertionError:assert(false)// PHP7.4Warning:assert():assert(false)failed

PHP7.4以前と同じ動作に戻すにはini設定assert.exception=0を設定します。

ちなみにPHP7.0以降、アサート文はコンパイル時に除去されて実行コストが0になるので、気軽に突っ込んでおけます。
便利なのでどんどん使いましょう。

Removed ability to call non-static methods statically.

静的でないメソッドを静的に呼び出すことができなくなりました。

classHOGE{publicfunctionfuga(){}}HOGE::fuga();// PHP8.0Fatalerror:UncaughtError:Non-staticmethodHOGE::fuga()cannotbecalledstatically// PHP7.4Deprecated:Non-staticmethodHOGE::fuga()shouldnotbecalledstatically

これまでは警告は出るものの実行自体はできていました。
今後は致命的エラーになります。

Removed (unset) cast.

(unset)キャストが削除されました。

$a=1;(unset)$a;// PHP8.0Fatalerror:The(unset)castisnolongersupported// PHP7.4Deprecated:The(unset)castisdeprecated

今後は普通にunset($a);としましょう。

Removed track_errors ini directive.

ini設定track_errorsが削除されました。

これは何かというと$php_errormsgです。
track_errorsが有効になっていると、最後に発生したエラーメッセージが$php_errormsgに登録されるという謎機能です。
デフォルトはずっとオフで、またPHP7.2でE_DEPRECATEDになったので使っている人もほとんどいないでしょうが、今後はerror_get_lastを使いましょう。

Removed the ability to define case-insensitive constants.

defineの第三引数$case_insensitiveが削除されました。

define('HOGE','FUGA',true);var_dump(HOGE,HoGe);// PHP8.0Warning:define():Argument#3 ($case_insensitive) is ignored// PHP7.4FUGA,FUGA// Deprecated: define(): Declaration of case-insensitive constants is deprecated

trueにすると定数が大文字小文字を区別しなくなるという意味のわからない機能です。

PHPは大文字小文字を区別するかしないかはわりかしややこしいのですが、関数/メソッドは区別しない、それ以外は区別する、という認識でだいたい大丈夫です。
実装上は、一律して区別するものだと考えておいたほうが楽でしょう。

Access to undefined constants now always results in an Error exception.

未定義定数にアクセスすると致命的エラーが発生します。

define('HOGE','FUGA',true);var_dump(HOGE,HoGe);// PHP8.0Fatalerror:UncaughtError:Undefinedconstant"HOGE"// PHP7.4HOGE// Warning: Use of undefined constant HOGE - assumed 'HOGE'

これまではE_WARNINGを出したうえで、定数名と同じ文字列が割り当てられていましたが、この手抜きができなくなります。

Removed ability to specify an autoloader using an __autoload() function.

__autoload関数が削除されました。

function__autoload($class){}// PHP8.0Fatalerror:__autoload()isnolongersupported,usespl_autoload_register()instead// PHP7.4Deprecated:__autoload()isdeprecated,usespl_autoload_register()instead

削除されたといっても完全に消えたわけではなく、定義することもできないという特別扱いです。

今後はspl_autoload_registerを使いましょう。
Composerのオートロードとか使った方がもっといいですが。

Removed the $errcontext argument for custom error handlers.

set_error_handlerの第1引数$error_handlerの第5引数$errcontextが削除されました。

set_error_handler(function($errno,$errstr,$errfile,$errline,$errcontext){echo$errcontext['fuga'];});functionhoge(){$fuga='piyo';$y='1a'+1;}hoge();// PHP8.0Fatalerror:UncaughtArgumentCountError:Toofewargumentstofunction{closure}(),4passedandexactly5expected// PHP7.4"piyo"

エラーが発生した個所のローカル変数が配列で入ってくるという謎機能です。

Removed create_function().

PHPの魔関数のひとつcreate_functionが削除されました。

$a=create_function('$a','echo $a;');$a('hoge');// PHP8.0Fatalerror:UncaughtError:Calltoundefinedfunctioncreate_function// PHP7.4"hoge"// Deprecated: Function create_function() is deprecated

かわりに無名関数を使いましょう。
無名関数はPHP5.3から使えるので、古のソースを熟成させながら使い続けてでもいないかぎり、いまどきcreate_functionはそうそう出てこないはずです。

Removed each()

eachが削除されました。

$arr=[1,2,3];while([$key,$val]=each($arr)){var_dump($key,$val);}// PHP8.0Fatalerror:UncaughtError:Calltoundefinedfunctioneach()// PHP7.40,11,22,3// Deprecated: The each() function is deprecated

この関数を使う意味は全くないので、普通にforeach使いましょう

Removed ability to unbind $this from closures

クロージャ内で$thisのバインドを外すことができなくなりました。
とあるのだけどよくわかりません。

$closure=Closure::bind(null,newstdClass());// PHP8.0Fatalerror:UncaughtTypeError:Closure::bind():Argument#1 ($closure) must be of type Closure, null given// PHP7.4Warning:Closure::bind()expectsparameter1tobeClosure,nullgiven

これは何の意味があるんだ?

Removed ability to use array_key_exists() with objects

オブジェクトに対してarray_key_existsを使えなくなりました。

array_key_exists(1,(object)[0,1]);// PHP8.0Fatalerror:UncaughtTypeError:array_key_exists():Argument#2 ($array) must be of type array, stdClass given// PHP7.4Deprecated:array_key_exists():Usingarray_key_exists()onobjectsisdeprecated

property_existsを使えってずっと前から言われていたので、今さらこれに引っかかることはないでしょう。

Made the behavior of array_key_exists() regarding the type of the key parameter consistent with isset() and normal array access.

array_key_existsの引数のキー値の挙動が、issetなどと同じになりました。

array_key_exists([],[1]);// PHP8.0Fatalerror:UncaughtTypeError:Illegaloffsettype// PHP7.4Warning:array_key_exists():Thefirstargumentshouldbeeitherastringoranintegerisset([],[1]);// こちらは昔からFatal error

これまでは引数のキー値に配列やオブジェクトなど不正な値を突っ込むことができましたが(当然falseなので意味はない)、今後はissetなどと同様のチェックが入ります。

negative_array_index

配列の自動採番キーがマイナスに対応します。

$a=[-10=>1];$a[]=2;// PHP8.0$a[-9]=>2になる// PHP7.4$a[0]=>2になる

これは正直、どうして賛成多数なのかわからない。

The default error_reporting level is now E_ALL.

ini設定error_reportingのデフォルトがE_ALLになります。
これまではE_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATEDでした。

この変更により、適当に書いてるコードは動かなくなります。

echo$a;// PHP8.0Warning:Undefinedvariable$a// PHP7.4何も出ない

PHP7.4で何も出ないのは単にデフォルトが非表示になっているだけなので、E_ALLに設定変更すればエラーが出ます。

もちろんerror_reportingを変更すれば黙殺することもできますが、やめましょう。

display_startup_errors is now enabled by default.

ini設定display_startup_errorsの初期値がオンになりました。

Using "parent" inside a class that has no parent will now result in a fatal compile-time error.

親クラスの無いクラスでparentを書くとコンパイルエラーになります。

classA{publicfunction__construct(){parent::__construct();}}// PHP8.0Fatalerror:Cannotuse"parent"whencurrentclassscopehasnoparent// PHP7.4Deprecated:Cannotuse"parent"whencurrentclassscopehasnoparent

PHP7.4では、呼ばれないかぎりは警告にとどまります。
もちろんnew A()を実行したら、parentが存在しないため致命的エラーになります。

The @ operator will no longer silence fatal errors

エラー制御演算子@が致命的エラーには効かなくなりました。

@require("notfound.php");// PHP8.0Fatalerror:UncaughtError:Failedopeningrequired'notfound.php'Processexitedwithcode255.// PHP7.4Processexitedwithcode255.

もっとも致命的エラーが起きたらスクリプトは強制終了されるので、結果は特に変わりません。

Following the hash comment operator # immediately with an opening bracket is not supported as a comment

#[はコメントにならなくなりました。

#[ これはコメント// PHP8.0Parseerror:Unclosed'['// PHP7.4エラーは起きない

アトリビュートの実装に伴う変更です。
[以外の文字はこれまでどおりコメントです。
空白を入れた# [もコメントになります。

LSP violations will now always generate a fatal error

LSP違反となる継承は常に致命的エラーを発生します。

classC1{publicfunctionmethod(array$a){}}classC2extendsC1{publicfunctionmethod(int$a){}}// PHP8.0Fatalerror:DeclarationofC2::method(int$a)mustbecompatiblewithC1::method(array$a)// PHP7.4Warning:DeclarationofC2::method(int$a)shouldbecompatiblewithC1::method(array$a)

これまでは場合によってE_FATALだったりE_WARNINGだったりしていたので、これを揃えたものです。

The precedence of the concatenation operator has changed

連結演算子の優先度が変更されます。

$errors_count=0;echo'unknown_upgrade_error_'.$errors_count+1;// PHP8.0unknown_upgrade_error_1// PHP7.41

これまで.+の優先順位が同じで前から順だったため、直感的ではない結果になることがありました。
今後は.の優先順位が下がります。

Arguments with a default value that resolves to null at runtime will no longer implicitly mark the argument type as nullable

引数のデフォルト値にnullが指定されている場合、引数の型は暗黙的にnull許容型になります。

functiontest(int$arg=null){}test(null);

型引数はintですが、デフォルト値にnullが指定されているので暗黙的に?int型となります。
このようにnullを直接渡した場合の挙動はPHP8でも変わりません。

しかし、デフォルト値を定数などで間接的に渡した場合は暗黙のnull許容型が許されなくなります。

constCONST_RESOLVING_TO_NULL=null;functiontest(int$arg=CONST_RESOLVING_TO_NULL){}test(null);// PHP8.0Fatalerror:UncaughtTypeError:test():Argument#1 ($arg) must be of type int, null given// PHP7.4エラーは出ない

一件ややこしいですが、まあnull許容型の意味を考えれば妥当な変更かなと。

A number of warnings have been converted into Error exceptions

多くのE_NOTICEがE_WARNINGに、多くのE_WARNINGが例外にと、警告レベルが厳しくなります

$a=newstdClass();$a->b;// PHP8.0Warning:Undefinedproperty:stdClass::$b// PHP7.4Notice:Undefinedproperty:stdClass::$b$a=1;$a->b++;// PHP8.0Fatalerror:UncaughtError:Attempttoincrement/decrementproperty"b"// PHP7.4Warning:Attempttoincrement/decrementproperty'b'ofnon-object

横着せずに正しいコードを書くようにしましょう。

Attempting to assign multiple bytes to a string offset will now emit a warning

マルチバイト文字列にオフセットアクセスするとE_WARNINGが出るようになります。

<?php$str='あいうえお';$str[2]='か';// PHP8.0Warning:Onlythefirstbytewillbeassignedtothestringoffset// PHP7.4何も出ない

なんにしろ結果は文字化けするので、このようなコードを書いている時点でおそらくバグでしょう。

Unexpected characters in source files will now result in a ParseError

ヌルバイトなど、ソースコード中に想定外の文字コードが入っているとパースエラーになります。
これまではE_COMPILE_WARNINGでした。

Uncaught exceptions now go through "clean shutdown"

"destructors will be called after an uncaught exception"、すなわちキャッチされない例外が発生してもデストラクタが呼ばれるようになる、と読めるのですが、でも実際は前から呼ばれてるんですよね。
なんのことかよくわかりません。

classHOGE{publicfunctionfuga(){thrownew\Exception();}publicfunction__destruct(){echo'destruct called.';}}(newHOGE())->fuga();// PHP8も7.4もdestructcalled.Fatalerror:UncaughtException

Compile time fatal error "Only variables can be passed by reference" has been delayed until runtime

参照渡し引数に値を渡した際の警告タイミングが変更になりました。

try{array_pop([1,2,3]);}catch(\Throwable$e){echo$e->getMessage();}// PHP8.0array_pop():Argument#1 ($array) cannot be passed by reference// PHP7.4Fatalerror:Onlyvariablescanbepassedbyreference

PHP7.4まではコンパイル時にエラーが出ていたので、プログラム側で制御することができませんでした。
PHP8では評価が実行時まで遅延されるので、結果としてcatchで受け取ることができるようになります。
まあソースコードを修正すべき内容なので、catchできても特に意味はなさそうですが。

Some "Only variables should be passed by reference" notices have been converted to "Argument cannot be passed by reference" exception.

一部の参照渡し引数に値を渡した時の挙動がE_NOTICEから例外になりました。
とあるのですが実例を見つけられませんでした。

array_pop([1,2,3]);// Fatal errorarray_pop(array_values([1,2,3]));// Notice: Only variables should be passed by reference

PHP7のころから、値を直接渡した場合はFatal errorとなり、別の関数の返り値をそのまま渡すとE_NOTICEになります。

The generated name for anonymous classes has changed

匿名クラスの名前が変更になりました。

var_dump(newclassextendsstdClass{});// PHP8.0object(stdClass@anonymous)// PHP7.4object(class@anonymous)

名前に親クラスやインターフェイスの名前が付くようになり、わかりやすくなります。
しかし、これのせいで互換性が失われる実装って想像もつきませんな。

Non-absolute trait method references in trait alias adaptations are now required to be unambiguous

トレイトに同じ名前がある場合、曖昧さを消さなければならなくなりました。

traitT1{publicfunctionfoo(){}}traitT2{publicfunctionfoo(){}}classX{useT1,T2{fooASbar;}publicfunctionfoo(){}}// PHP8.0Fatalerror:Analiaswasdefinedformethodfoo(),whichexistsinbothT1andT2// PHP7.4何もエラー出ない

X::foo()はどれを指すのかが曖昧ですが、PHP7.4では暗黙的にT1::foo()とみなされていました。
PHP8.0では以下のように明示しなければなりません。

classX{useT1,T2{T1::fooASbar;}}

The signature of abstract methods defined in traits is now checked against the implementing class method

traitに書いた抽象メソッドを実装したときにシグネチャを正しく解析するようになりました。

traitMyTrait{abstractpublicfunctionneededByTrait():string;}classMyClass{useMyTrait;publicfunctionneededByTrait():int{return42;}}// PHP8.0Fatalerror:DeclarationofMyClass::neededByTrait()mustbecompatiblewithMyTrait::neededByTrait()// PHP7.4何もエラー出ない

今まで異なるシグネチャで実装できていたのがバグなのではという気がしないでもない。

Disabled functions are now treated exactly like non-existent functions

無効化した関数が存在しない関数と同じ扱いになりました。

具体的には、php.inidisable_functions ="exec"と設定したときの結果が異なります。

exec('ls');// PHP8.0Fatalerror:UncaughtError:Calltoundefinedfunctionexec()// PHP7.4PHPWarning:exec()hasbeendisabledforsecurityreasons

PHP7.4までのdisable_functionsは、『存在はしているけど無効化されている』という扱いでした。
PHP8においては単純に『存在しない』となるので、別の定義を行うことも可能です。

data: stream wrappers are no longer writable

dataストリームラッパーに書き込みできなくなりました。

The arithmetic and bitwise operators will now consistently throw a TypeError

各種演算子が、引数に配列、リソース、オブジェクトが渡された場合にTypeErrorを出すようになりました。
対象の演算子は+-*/**%<<>>&|^~++--です。

newstdClass()+1;// PHP8.0Fatalerror:UncaughtTypeError:Unsupportedoperandtypes:stdClass+int// PHP7.4Notice:ObjectofclassstdClasscouldnotbeconvertedtonumber

オブジェクトの場合、GMPのように演算子オーバーロードが設定されている一部のクラスはこれまでどおり計算可能です。

Float to string casting will now always behave locale-independently

浮動小数から文字列へのキャストがロケールに依存しなくなりました。

setlocale(LC_ALL,'fr-FR');echo(string)3.14;// PHP8.03.14// PHP7.43,14

フランス語は小数点が','なので、これまでは3,14になっていました。
しかし(float)"3,14"は解釈できず元に戻せなかったりと、わりと中途半端な機能だったので、ロケールに関わらず常に3.14にするようになりました。

Removed support for deprecated curly braces for offset access

中括弧による文字列オフセットアクセスが削除されました。

echo'12345'{3};// PHP8.0Fatalerror:Arrayandstringoffsetaccesssyntaxwithcurlybracesisnolongersupported// PHP7.44Deprecated:Arrayandstringoffsetaccesssyntaxwithcurlybracesisdeprecated

何のために存在したのかよくわからない機能です。

Applying the final modifier on a private method will now produce a warning unless that method is the constructor

コンストラクタ以外のprivateメソッドにfinalを書けなくなりました。

classFOO{finalprivatefunctionbar(){}}// PHP8.0Warning:Privatemethodscannotbefinalastheyareneveroverriddenbyotherclasses// PHP7.4何も出ない

privateメソッドはオーバーライドされることはないよ、というE_WARNINGが出ます。
警告なので動作自体はするのですが、今後動かなくなる可能性もありますし、使わない方がよいでしょう。

If an object constructor exit()s, the object destructor will no longer be called

コンストラクタでexit()した場合、デストラクタが呼ばれなくなりました。

classFOO{publicfunction__construct(){exit();}publicfunction__destruct(){echo'destruct called.';}}newFOO();// PHP8.0何も出ない// PHP7.4destructcalled.

元々コンストラクタでthrowしたときはデストラクタが呼ばれていなかったのですが、それと動作を合わせたということらしいです。

Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings

厳密でない比較演算子の数値比較の挙動が変更になりました。
詳しくはここに書いてあります

var_dump('foo'==0);// PHP8.0false// PHP7.4true

厳密な比較演算子の挙動は変更ありません。
===を使っている限りは安泰です。

Namespaced names can no longer contain whitespace

名前空間に空白を入れることができなくなりました。

namespaceA\B{}// PHP8.0Parseerror:syntaxerror,unexpectedtoken"\"
// PHP7.4
エラー出ない

まあ、今までできていたのがおかしいといえばおかしいのですが。

Nested ternaries now require explicit parentheses

曖昧な三項演算子のネストに括弧が必要になりました。

1?2:3?:4;// PHP8.0Fatalerror:Unparenthesized`a ? b : c ?: d`isnotsupported// PHP7.4Deprecated:Unparenthesized`a ? b : c ?: d`isdeprecated

PHPの三項演算子は他の大半の言語と挙動が異なるという問題がありましたが、それを合わせるための布石です。

debug_backtrace() and Exception::getTrace() will no longer provide references to arguments

debug_backtraceおよびException::getTraceが引数の参照を渡さなくなりました。

functionfoo(&$bar){debug_backtrace()[0]['args'][0]=2;}$x=1;foo($x);echo$x;// PHP8.01// PHP7.42

これまでスタックトレース経由で引数を書き替えるという邪悪な操作ができていたのですが、今後はできなくなります。

Numeric string handling has been altered to be more intuitive and less error-prone

数値型文字列の定義が変更になりました

functionfoo(int$int){}foo('123abc');// PHP8.0Fatalerror:UncaughtTypeError:foo():Argument#1 ($int) must be of type int// PHP7.4Notice:Anonwellformednumericvalueencountered

PHP7.4までは数値型文字列の定義が『数値型文字列』と『非正規の数値型文字列』の2種類あってわかりにくかったのですが、今後は単純に『数値型文字列』とそれ以外になります。

Magic Methods will now have their arguments and return types checked if they have them declared

マジックメソッドがシグネチャをチェックするようになりました。

classFOO{publicfunction__get(array$name):int{return1;}}// PHP8.0PHPFatalerror:FOO::__get():Parameter#1 ($name) must be of type string when declared// PHP7.4エラー出ない

正しい定義に合わせるか、あるいは単にシグネチャを書かないようにすればよいです。

// PHP8.0でもOKclassFOO{publicfunction__get($name){return1;}}

call_user_func_array() array keys will now be interpreted as parameter names, instead of being silently ignored

call_user_func_arrayに連想配列を渡したときに、キーが無視されなくなりました。

functionfoo(...$args){var_dump($args);}call_user_func_array('foo',['a'=>1,'b'=>2]);// PHP8.0['a'=>1,'b'=>2]// PHP7.4[1,2]

そもそもcall_user_func_arrayなんか使うなって話だな。

COM

Removed the ability to import case-insensitive constants from type libraries

COMのタイプライブラリ定数の大文字小文字を区別しない機能が削除されました。
com_load_typelibの第二引数は常にtrueとなり、com.autoregister_casesensitiveも常にonとなります。

ということらしいのだけど、そもそもタイプライブラリって何だ。

Curl

CURLOPT_POSTFIELDS no longer accepts objects as arrays

CURLOPT_POSTFIELDSはオブジェクトを受け取らなくなりました。

$c=curl_init();curl_setopt($c,CURLOPT_POSTFIELDS,(object)['a'=>1]);// PHP8.0Fatalerror:UncaughtError:ObjectofclassstdClasscouldnotbeconvertedtostring// PHP7.4エラー出ない

そもそも最初から文字列か配列しか受け取らないという仕様で、オブジェクトを受け取れていたのはたまたまです。
今後は普通に配列を渡せば問題ありません。

Date

mktime() and gmmktime() now require at least one argument

mktimegmmktimeは、最低ひとつの引数が必要になりました。

mktime();// PHP8.0Fatalerror:UncaughtArgumentCountError:mktime()expectsatleast1argument,0given// PHP7.4Deprecated:mktime():Youshouldbeusingthetime()

単に現在時刻がほしいときはtimeを使え、ということらしいです。

DOM

Remove unimplemented classes from ext/dom that had no behavior and contained test data

定義だけあって実装のなかった、あるいは実験的実装だったDOM関連クラスが削除されました。

newDOMTypeInfo();// PHP8.0Fatalerror:UncaughtError:Class"DOMTypeInfo"notfound// PHP7.4エラー出ない

具体的にはDOMNameList / DomImplementationList / DOMConfiguration / DomError / DomErrorHandler / DOMImplementationSource / DOMLocator / DOMUserDataHandler / DOMTypeInfoが削除されました。
これらはDOMスタンダードからも削除されているため、それと合わせたものとなります。
マニュアルにも元々入ってなかったので影響も極小でしょう。

Enchant

enchant_broker_list_dicts(), enchant_broker_describe() and enchant_dict_suggest() will now return an empty array instead of null

enchant_broker_list_dicts等の関数が、対象がなにもないときにnullではなく[]を返すようになりました。

enchant_broker_init() will now return an EnchantBroker object rather than a resource

enchant_broker_initは、これまでリソースを返していたのがEnchantBrokerオブジェクトを返すようになりました。

他のEnchant関数はこれまでと同じ書き方で透過的に動作します。

enchant_broker_request_dict() and enchant_broker_request_pwl_dict() will now return an EnchantDictionary object rather than a resource

enchant_broker_request_dictenchant_broker_request_pwl_dictは、これまでリソースを返していたのがEnchantDictionaryオブジェクトを返すようになりました。

ていうかEnchantってPHP7.3で削除されるという話だったんだけどどうなったんだ?

Exif

Removed read_exif_data

read_exif_dataが削除されました。

今後はexif_read_dataを使いましょう。

Filter

The FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED flags for the FILTER_VALIDATE_URL filter have been removed

検証フィルタFILTER_VALIDATE_URLにおいて、FILTER_FLAG_SCHEME_REQUIREDFILTER_FLAG_HOST_REQUIREDのフラグが削除されました。

実はプロトコルスキームとホストは元から常に必須だったため、実質的に意味のないフラグでした。

The INPUT_REQUEST and INPUT_SESSION source for filter_input() etc have been removed

filter_inputなどのフラグINPUT_REQUESTとINPUT_SESSIONが削除されました。

そもそも実装されていませんでした。

GD

The GD extension now uses a GdImage objects as the underlying data structure for images, rather than resources

GDリソースがGdImageオブジェクトになりました。

$image=imagecreatetruecolor(100,100);$text_color=imagecolorallocate($image,233,14,91);imagestring($image,1,5,5,'TEXT',$text_color);imagepng($image);echogettype($image);// PHP8.0object// PHP7.4resource

この変更は透過的です。
上記コードの$imageはPHP7.4ではリソースであるのに対してPHP8.0ではオブジェクトになりますが、どちらでも同じように動作します。

ただしis_resourceなどでチェックを入れている場合は動かなくなります。

The deprecated function image2wbmp() has been removed

image2wbmp関数が削除されました。

PHP7.3以降E_DEPRECATEでした。

The deprecated functions png2wbmp() and jpeg2wbmp() have been removed

同じく非推奨だったpng2wbmpjpeg2wbmpも削除されました。

The default $mode parameter of imagecropauto() no longer accepts -1.

imagecropautoの第二引数$mode-1を受け付けなくなりました。

$image=imagecreatetruecolor(100,100);imagecropauto($image,-1,0.5);// PHP8.0Fatalerror:UncaughtValueError:imagecropauto():Argument#2 ($mode) must be a valid mode// PHP7.4Deprecated:imagecropauto():Cropmode-1isdeprecated

IMG_CROP_DEFAULTなどの定数を使いましょう。

GMP

gmp_random() has been removed

gmp_randomが削除されました。

この関数はプラットフォームに依存して出力が変わるという問題があったため、PHP7.2でE_DEPRECATEDになりました。
かわりにgmp_random_bitsgmp_random_rangeを使いましょう。

Iconv

iconv() implementations which do not properly set errno in case of errors are no longer supported

iconvは、エラー時にerrnoプロパティを適切にセットしない実装はサポートしなくなりました。

と書かれているのですが、errnoがなんなのか一切出てこないので何を見て判断すればよいのかわかりません。

IMAP

The unused default_host argument of imap_headerinfo() has been removed

imap_headerinfoの未使用だった第五引数$defaulthostが削除されました。

The imap_header() function which is an alias of imap_headerinfo() has been removed

imap_headerが削除されました。

imap_headerinfoのエイリアスです。

Intl

The deprecated constant INTL_IDNA_VARIANT_2003 has been removed

定数INTL_IDNA_VARIANT_2003が削除されました。

これはUnicodeから削除されたためです。

The deprecated Normalizer::NONE constant has been removed

Normalizer::NONEが削除されました。

何もしないという意味のない設定です。

The IntlDateFormatter::RELATIVE_FULL, RELATIVE_LONG, RELATIVE_MEDIUM, and RELATIVE_SHORT constants have been added.

IntlDateFormatterクラスに定数RELATIVE_FULL/RELATIVE_LONG/RELATIVE_MEDIUM/RELATIVE_SHORTが追加されました。

追加は互換性のない変更ではないような気がする。

LDAP

The deprecated function ldap_sort / ldap_control_paged_result / ldap_control_paged_result_response has been removed

関数ldap_sortldap_control_paged_resultldap_control_paged_result_responseが削除されました。

かわりにldap_searchを使いましょう。

The interface of ldap_set_rebind_proc has changed

ldap_set_rebind_procの第二引数$callbackが空白""を受け付けなくなりました。

設定を外したい場合はかわりにnullを使います。

Mbstring

The mbstring.func_overload directive has been removed

マルチバイト関数の関数オーバーロード機能が削除されました。

substrを使うと自動的にmb_substrが呼ばれる、といった機能なのですが、事故の元でしかありません。

機能の削除に伴い、定数MB_OVERLOAD_MAILmb_get_infofunc_overloadといった関連項目も削除されます。

mb_parse_str() can no longer be used without specifying a result array

mb_parse_strの第二引数$arrayが必須になりました。

mb_parse_str('a=b');echo$a;// PHP8.0Fatalerror:UncaughtArgumentCountError:mb_parse_str()expectsexactly2arguments,1given// PHP7.4b// Deprecated:  mb_parse_str(): Calling mb_parse_str() without the result argument is deprecated

元々は文字列を直接変数に展開するという危険極まりない関数だったのですが、この変更により配列に展開するという妥当な内容になりました。
$array = mb_parse_str('a=b')とできればもっと良かったのですけどね。

A number of deprecated mbregex aliases have been removed

いくつかのマルチバイト正規表現関数に存在したエイリアスが削除されました。

mbsplit("//u",'foo');// PHP8.0Fatalerror:UncaughtError:Calltoundefinedfunctionmbsplit// PHP7.4Deprecated:Functionmbsplit()isdeprecated

なぜかmb_eregmb_regex_encodingなどには、mberegmbregex_encodingといった_のないエイリアスが存在しました。
これらはマニュアルにも全く存在しない、謎のエイリアスです。

The 'e' modifier for mb_ereg_replace() has been removed

mb_ereg_replaceにおいてオプションeが削除されました。

preg_replaceでは7.0で削除されたのに何故かこっちには残っていたのですが、ようやく揃った形です。

今後はmb_ereg_replace_callbackを使う必要があります。

A non-string pattern argument to mb_ereg_replace() will now be interpreted as a string instead of an ASCII codepoint

mb_ereg_replaceにおいて、第一引数$patternのASCIIコード変換を行わなくなります。

echomb_ereg_replace(98,'x','abc98');// PHP8.0"abcx"// PHP7.4"axc98"// Deprecated:  mb_ereg_replace(): Non-string patterns will be interpreted as strings in the future

第一引数に数値を渡した場合、これまでは何故か対応するASCIIコードとして扱われていました。
意味もないうえにわかりにくすぎるので、今後は単純に文字列として扱われます。

The needle argument for mb_strpos(), mb_strrpos(), mb_stripos(), mb_strripos(), mb_strstr(), mb_stristr(), mb_strrchr() and mb_strrichr() can now be empty

mb_strposなどの各関数において、引数$needleに空白が許可されます。

echomb_strpos('abcde','');// PHP8.00// PHP7.4false// Warning:  mb_strpos(): Empty delimiter

""はあらゆる文字列にマッチするため、だいたい1文字目になります。

The $is_hex parameter, which was not used internally, has been removed from mb_decode_numericentity()

mb_decode_numericentityにおいて、使われていなかった引数$is_hexが削除されました。

The legacy behavior of passing the encoding as the third argument instead of an offset for the mb_strrpos() function has been removed

mb_strrposの、引数$encodingは第四引数ですが、これを第三引数に書いても動く機能が削除されました。

mb_strrpos('b','abc','UTF-8');// PHP8.0Fatalerror:UncaughtTypeError:mb_strrpos():Argument#3 ($offset) must be of type int, string given// PHP7.4Deprecated:mb_strrpos():Passingtheencodingasthirdparameterisdeprecated

引数の位置が変更されたのはPHP5.2です。
今まで残ってたことにびっくりですね。

The ISO_8859-* character encoding aliases have been replaced by ISO8859-* aliases

サポートされる文字エンコーディングのうち、ISO-8859-xのエイリアスが変更されました。

mb_detect_order(['ISO-8859-1','ISO_8859-2']);var_dump(mb_detect_order());// PHP8.0Fatalerror:UncaughtValueError:mb_detect_order():Argument#1 ($encoding) contains invalid encoding// PHP7.4['ISO-8859-1','ISO-8859-2']

これまでISO_8859-xという形のエイリアスが存在したのですが、PHP8.0では使えなくなりました。
かわりにISO8859-xというエイリアスが使えるようになりますが、これはPHP7.4では対応していません。

iconvと形を揃えるためだそうですが、いきなり完全に差し替える必要に陥ります。
とはいえ、最初からエイリアスではなくISO-8859-xの正しい形を使っていれば特に問題ありません。

mb_ereg() and mb_eregi() will now return boolean true on a successful match

mb_eregmb_eregiが、マッチしたらtrueを返すようになりました。

echomb_ereg('bbb','abbbc',$regs);// PHP8.0true// PHP7.43

これまでは第三引数$regsの有無によって返り値の値も型も変わるという非常に使いにくいものでした。
この変更によって、マッチしたらtrue、しなかったらfalseとわかりやすい形になります。

OCI8

The OCI-Lob class is now called OCILob, and the OCI-Collection class is now called OCICollection

OCI-LobクラスがOCILobに、OCI-CollectionクラスがOCICollectionに変更されました。

Several alias functions have been marked as deprecated

幾つかの関数のエイリアスが非推奨になりました。

oci_internal_debug() and its alias ociinternaldebug() have been removed

oci_internal_debugが削除されました。

ODBC

odbc_connect() no longer reuses persistent connections

odbc_connectが持続的接続を利用しなくなりました。

よくわかりませんが、odbc_pconnectのほうに同じ dsn、user、 password の組み合わせ (odbc_connect() および odbc_pconnect() による)接続の場合は、 持続的な接続を再利用するとか書いてあるので、おそらく一度odbc_pconnectしたあとにodbc_connectしたら持続的接続になってしまっていたのではないかと思われます。

The unused flags parameter of odbc_exec() has been removed

odbc_execの第三引数$flagsは未使用だったため削除されました。

OpenSSL

openssl_x509_read() and openssl_csr_sign() will now return an OpenSSLCertificate object rather than a resource

openssl_x509_readopenssl_csr_signは、これまでリソースを返していたのをOpenSSLCertificateオブジェクトを返すようになりました。

The openssl_x509_free() function is deprecated

openssl_x509_freeはE_DEPRECATEDとなり、何もしなくなりました。

↑の変更で対象がリソースからオブジェクトになったので、わざわざ関数で開放しなくても自動的に解放されるからです。

openssl_csr_new() will now return an OpenSSLCertificateSigningRequest object rather than a resource

openssl_csr_newもリソースではなくOpenSSLCertificateSigningRequestオブジェクトを返すようになりました。

openssl_pkey_new() will now return an OpenSSLAsymmetricKey object rather than a resource

openssl_pkey_newもOpenSSLAsymmetricKeyオブジェクトを以下略

The openssl_pkey_free() function is deprecated

openssl_pkey_freeはE_DEPRECATEDとなり、何もしなくなりました。

openssl_seal() and openssl_open() now require $method to be passed

openssl_sealopenssl_openの引数$methodが必須になりました。
デフォルト値が'RC4'で、これはセキュアではないためです。

PCRE

When passing invalid escape sequences they are no longer interpreted as literals

無効なエスケープシーエンスが文字列リテラルと解釈されなくなりました。

preg_match('/\i/','h\ij',$matches);var_dump($matches);// PHP8.0null// Warning:  preg_match(): Compilation failed: unrecognized character// PHP7.4[0=>"i"]

正規表現パターンに存在しない文字列\iは、これまでは単なる文字列と解釈されていましたが、今後は不正なパターンとみなされてエラーが出るようになります。
\iという文字列で検索したい場合は、正しく\\\\iと記述しましょう。

PDO

The default error handling mode has been changed from "silent" to "exceptions"

PDOエラーモードPDO::ATTR_ERRMODEのデフォルト値がPDO::ERRMODE_EXCEPTIONになりました。
これまではPDO::ERRMODE_SILENTでした。

The signatures of some PDO methods have changed

幾つかのメソッドにおいてシグネチャが変更されました。
例としてPDOStatement::setFetchModeは、PDOStatement::setFetchMode(int $mode, ...$params)になります。

PDO_ODBC

The php.ini directive pdo_odbc.db2_instance_name has been removed

pdo_odbc.db2_instance_nameディレクティブが削除されました。

これを設定すると環境変数DB2INSTANCEに値が入るだけというよくわからないディレクティブなので、まあ削除されても妥当でしょう。

pgsql

The deprecated pg_connect() syntax using multiple parameters instead of a connection string is no longer supported

pg_connectにおいて、DSNを使わない形の古い構文が削除されました。

pg_connect("host","port","options","tty","dbname");// PHP8.0Fatalerror:UncaughtArgumentCountError:pg_connect()expectsatmost2arguments,5given// PHP7.4エラー出ない

mysqliもPDOも既にDSN形式以外は対応していないので、こちらもいつまでも残しておく必要はないでしょう。

The deprecated pg_lo_import() and pg_lo_export() signature that passes the connection as the last argument is no longer supported

pg_lo_importおよびpg_lo_exportは、実は第三引数にリソースを渡しても動いていたらしいのですが、それが削除されました。

そんな構文ドキュメントにもユーザノートにも全く書かれていないのですが、PHP7.4のソースにはたしかにそれっぽいものが書いてあって、PHP8.0ではそれがなくなっていました。
これ使ってる人とかいるんだろうか。

01.png

pg_fetch_all() will now return an empty array instead of false for result sets with zero rows

pg_fetch_allは、取得行数が0だった場合はfalseを返していたのですが、[]を返すようになりました。

失敗ではなく結果が無いということなので、こちらが妥当でしょう。

Phar

Metadata associated with a phar will no longer be automatically unserialized

これまではPharファイルを読み込もうとした時点で自動的にメタデータが展開されていたのですが、自動的には呼ばれなくなりました。

セキュリティ上の理由です。

Reflection

The method signatures have been changed

幾つかの関数のシグネチャが変更されました。

// PHP7.4ReflectionClass::newInstance($args)ReflectionFunction::invoke($args)ReflectionMethod::invoke($object,$args)// PHP8.0ReflectionClass::newInstance(...$args)ReflectionFunction::invoke(...$args)ReflectionMethod::invoke($object,...$args)

The ReflectionType::__toString() method will now return a complete debug representation of the type, and is no longer deprecated

ReflectionType::__toStringは非推奨でなくなりました。

functionhoge(?int$a){}echo(newReflectionFunction('hoge'))->getParameters()[0]->getType();// PHP8.0?int// PHP7.4int

また、これまで正確に取ってこれなかったnullableなども取ってこれるようになっています。

Reflection export() methods have been removed

Reflection::exportは削除されました。

ReflectionFunction::export('strpos');// PHP8.0Fatalerror:UncaughtError:CalltoundefinedmethodReflectionFunction::export()// PHP7.4Function[<internal:standard>functionstrpos]

ざっくり概要確認するには便利だったんですけどね。

The following methods can now return information about default values of parameters of internal functions

ReflectionParameter::isDefaultValueAvailablegetDefaultValueisDefaultValueConstantgetDefaultValueConstantNameが内部関数にも使えるようになりました。

(newReflectionFunction('strpos'))->getParameters()[2]->getDefaultValue();// PHP8.00// PHP7.4Fatalerror:UncaughtReflectionException:Cannotdeterminedefaultvalueforinternalfunctions

内部関数に対して使う意義はあんまり感じられませんが。

ReflectionMethod::isConstructor() and ReflectionMethod::isDestructor() now also return true

ReflectionMethod::isConstructorおよびisDestructorは、インターフェイスにもtrueを返すようになりました。
これまではインターフェイスには非対応でした。

interfaceHOGE{publicfunction__construct();}(newReflectionFunction('strpos'))->getParameters()[2]->getDefaultValue();// PHP8.0true// PHP7.4false

ちなみにtraitには昔からtrueを返します。

ReflectionType::isBuiltin() method has been moved to ReflectionNamedType

ReflectionType::isBuiltinReflectionNamedTypeクラスに移動しました。
なぜならReflectionUnionTypeにはビルトインの型はないからです。

Sockets

The deprecated AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES flags for socket_addrinfo_lookup() have been removed

socket_addrinfo_lookup関数の第三引数に渡せるフラグAI_IDN_ALLOW_UNASSIGNED/AI_IDN_USE_STD3_ASCII_RULESが削除されました。

glibcで削除されたので追随したということのようです。

socket_create(), socket_create_listen(), etc will now return a Socket object rather than a resource

以下の各関数が、リソースではなくオブジェクトを返すようになりました。
socket_create / socket_create_listen / socket_accept / socket_import_stream / socket_addrinfo_connect / socket_addrinfo_bind / socket_wsaprotocol_info_import

$socket=socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);socket_set_option($socket,IPPROTO_IP,IP_MULTICAST_LOOP,0);var_dump($socket);// PHP8.0object(Socket)#1 (0) {}// PHP7.4resourceoftype(Socket)

socket_set_optionのようなソケットを引数として受け取る関数は、そのまま透過的に動作します。
ただしis_resource等でチェックしている場合は修正が必要です。

socket_addrinfo_lookup() will now return an array of AddressInfo objects rather than resources

socket_addrinfo_lookupは、リソースの配列ではなく、AddressInfoの配列を返すようになりました。

SPL

SplFileObject::fgetss() has been removed

SplFileObject::fgetssは削除されました。

SplHeap::compare($a, $b) now specifies a method signature

SplHeap::compareに型mixedが設定されました。
extendsする場合は型を指定するか、もしくは何も書かないかが必要です。

SplDoublyLinkedList::push() now returns void instead of true

SplDoublyLinkedList::pushがvoidを返すようになりました。

var_dump((newSplDoublyLinkedList())->push(1));// PHP8.0null// PHP7.4true

これまではtrueを返していました。
元々マニュアルにもvoidと書かれていて、trueを返すのはバグだったみたいです。

SplDoublyLinkedList::unshift() now returns void instead of true

SplDoublyLinkedList::unshiftがvoidを以下同文。

SplQueue::enqueue() now returns void instead of true

SplQueue::enqueueが以下同文。

spl_autoload_register() will now always throw a TypeError on invalid arguments

spl_autoload_registerは、無効な引数について常にTypeErrorを発するようになりました。

spl_autoload_register('HOGE',false);// PHP8.0Fatalerror:UncaughtTypeError:spl_autoload_register():Argument#1 ($callback) must be a valid callback, function "HOGE" not found or invalid function name// PHP7.4何も出ない

これに伴い、第二引数$throwは常に無視されるようになります。

SplFixedArray is now an IteratorAggregate and not an Iterator

SplFixedArrayIteratorAggregateをimplementsしました。

var_dump(is_subclass_of('SplFixedArray','Iterator'),is_subclass_of('SplFixedArray','IteratorAggregate'),);// PHP8.0false,true// PHP7.4true,false

これまではIteratorをimplementsしていました。
また、これに伴ってSplFixedArray::rewindなどIterator由来の実装は削除され、かわりにSplFixedArray::getIteratorが追加されます。

Standard

assert() will no longer evaluate string arguments

assertの引数を文字列表現で渡すことができなくなりました。

assert('$a');// PHP8.0true// PHP7.4Notice:Undefinedvariable:a

PHP7.4までは、引数が文字列のときはPHPコードとして解釈されていました。
つまりevalされていたってことです。

PHP8では'$a'という単なる文字列として扱われます。

parse_str() can no longer be used without specifying a result array

parse_strの第二引数$resultが必須になりました。
上の方にあるmb_parse_strと全く同じ理由です。

fgetss() has been removed

fgetssは削除されました。

The string.strip_tags filter has been removed

文字列フィルタstring.strip_tagsが削除されました。
fgetssなどと同様、何かをするのと同時に文字列をフィルタするのは事故の元なのでやめましょうという方向です。

The needle argument of strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr(), and stristr() will now always be interpreted as a string

strposほかの関数で、引数$needleに空文字列が有効になりました。

echostrpos('abc','');// PHP8.00// PHP7.4Warning:strpos():Emptyneedle

空文字はどのような文字列にも該当するので、だいたいは1文字目すなわち0になります。

The length argument for substr(), substr_count(), substr_compare(), and iconv_substr() can now be null

substrsubstr_countsubstr_compareiconv_substrの引数$lengthにnullを渡した時の挙動が変わりました。

echosubstr('abcde',2,null);// PHP8.0"cde"// PHP7.4""

これまでは返り値が0やら""やらになっていたのですが、これが未指定の場合と同じ動きになります。

The length argument for array_splice() can now be null

array_spliceの引数$lengthにnullを渡した時の挙動が変わりました。

$input=[1,2,3,4];array_splice($input,2,null);var_dump($input);// PHP8.0[1,2]// PHP7.4[1,2,3,4]

これまでは何もしませんでしたが、未指定の場合と同じ動きになります。
すなわち、引数$offsetより後ろが全て削除されます。

The args argument of vsprintf(), vfprintf(), and vprintf() must now be an array

vsprintfvfprintfvprintfの引数$argが配列しか受け付けなくなりました。

echovsprintf('a%sc','b');// PHP8.0Fatalerror:UncaughtTypeError:vsprintf():Argument#2 ($values) must be of type array, string given// PHP7.4abc

元からマニュアルでは配列のみとなっていたのに、何故か文字列なども受け付けていたという謎のサービスでした。

The 'salt' option of password_hash() is no longer supported

password_hashのオプションsaltが削除されました。
指定する意味はないし固定すると脆弱になるだけなので、元々存在する必要のないオプションです。

The quotemeta() function will now return an empty string if an empty string was passed

quotemetaにから文字列""を渡すと空文字列""を返すようになりました。
これまではfalseでした。

hebrevc() / convert_cyr_string() / money_format() / ezmlm_hash() / restore_include_path() has been removed

以下の関数が削除されました。
hebrevc
convert_cyr_string
money_format
ezmlm_hash
restore_include_path

上位互換が存在する、他の関数と整合性がないなどの理由で、PHP7.4で非推奨となっています。

get_magic_quotes_gpc() and get_magic_quotes_runtime() has been removed

旧時代PHPの黒歴史のひとつ、get_magic_quotes_gpcget_magic_quotes_runtimeが削除されました。
同時に定数FILTER_SANITIZE_MAGIC_QUOTESも削除されました。

PHPはついに、マジッククオートの軛から完全に解き放たれたのです。

Calling implode() with parameters in a reverse order ($pieces, $glue) is no longer supported

implodeは歴史的理由から引数を逆順でも受け付けていたのですが、これが削除されました。

echoimplode(['a','b','c'],'|');// PHP8.0Fatalerror:UncaughtTypeError:implode():Argument#2 ($array) must be of type ?array, string given// PHP7.4a|b|c

PHP8.0は、負の遺産の清算が目立ちます。

parse_url() will now distinguish absent and empty queries and fragments

parse_urlの、空のクエリやフラグメントへの返り値が微妙に変わりました。

// 出力のscheme等は省略var_dump(parse_url('http://example.com/foo'),parse_url('http://example.com/foo?'),parse_url('http://example.com/foo#'),parse_url('http://example.com/foo?#'),);// PHP8.0[],["query"=>""],["fragment"=>""],["query"=>"","fragment"=>""]// PHP7.4[],[],[],[]

空のクエリには空文字列を出力、クエリ自体がない場合は出力自体行わない、と区別できるようになります。

var_dump() and debug_zval_dump() will now print floating-point numbers using serialize_precision rather than precision

var_dumpdebug_zval_dumpの浮動小数出力が、ini設定precisionではなくserialize_precisionを使うようになりました。

ini_set('precision',1);ini_set('serialize_precision',100);var_dump(1.23456789012345678901234567890123456789012345678901234567890);// PHP8.0float(1.2345678901234566904321354741114191710948944091796875)// PHP7.4float(1)

100とか指定してもビット数の制限は越えられないみたい。

If the array returned by __sleep() contains non-existing properties, these are now silently ignored

マジックメソッド__sleepに存在しないプロパティを返した場合、無視するようになりました。

classFOO{private$a='a';publicfunction__sleep(){return['a','b'];}}echoserialize(newFOO());// PHP8.0O:3:"FOO":1:{s:6:"FOOa";s:1:"a";}// Warning:  serialize(): "b" returned as member variable from __sleep() but does not exist// PHP7.4O:3:"FOO":2:{s:6:"FOOa";s:1:"a";s:1:"b";N;}// Notice:  serialize(): "b" returned as member variable from __sleep() but does not exist

これまでは、値がnullのプロパティがセットされていました。

The default locale on startup is now always "C"

デフォルトのロケールが常に"C"になりました。
これまではLC_ALLは"C"で、LC_CTYPEは環境変数LANGから取ってくる、みたいなことになっていました。

Removed deprecated DES fallback in crypt()

cryptのSALTフォールバックが削除されました。

echocrypt('str','あ');// PHP8.0*0// PHP7.4UYLTFzPe08.// Deprecated:  crypt(): Supplied salt is not valid for DES

cryptはSALTの形式によって自動的にハッシュ形式を選択するのですが、これまでは未知のSALTが来た場合は自動的にDESにフォールバックしていました。
今後は失敗します。
ただ失敗といっても例外を出したりせず'*0'という文字列を返してくるのでむしろわかりにくいのでは。

Calling crypt() without an explicit salt is no longer supported

cryptの第二引数$saltが必須になりました。

echocrypt('str');// PHP8.0Fatalerror:UncaughtArgumentCountError:crypt()expectsexactly2arguments,1given// PHP7.4$1$SsnnMRiS$4clL.zBKekzZvryhRYVUP1// Notice:  crypt(): No salt parameter was specified

こちらは非対応SALTとは異なり、致命的エラーになります。

Sort comparison functions that return true or false will now throw a deprecation warning

ソート関数でtrue/falseを返している場合、非推奨の警告が出るようになりました。
0と等しいか、0より大きいか、0より小さい整数を返す必要があります。

$arr=[2,1];usort($arr,fn($a,$b)=>$a>$b);var_dump($arr);// PHP8.0[1,2]// Deprecated:  usort(): Returning bool from comparison function is deprecated// PHP7.4[1,2]

Any functions accepting callbacks that are not explicitly specified to accept parameters by reference will now warn

リファレンスを受け取らないコールバック関数の引数にリファレンスを書いた場合、警告が出るようになりました。

array_filter([1,2],function(&$v){returntrue;});// PHP8.0Warning:{closure}():Argument#1 ($v) must be passed by reference, value given// PHP7.4何も出ない

多くの関数では既にこうなっていたものの、array_filterなど一部はそうなってなかったので追加したということのようです。
それに$vを書き替えても元の値には影響しないので、&を付ける意味は特にないです。

HTTP stream wrapper as used by functions now advertises HTTP/1.1 rather than HTTP/1.0

stream_context_createなどで作れるHTTPストリームラッパーのデフォルトがHTTP1.1になりました。

これまでどおりHTTP1.0を使いたい場合は、コンテキストオプションで指定する必要があります。

$opts=['http'=>['protocol_version'=>'1.0',]];$context=stream_context_create($opts);

substr(), mb_substr(), iconv_substr() and grapheme_substr() now consistently clamp out-of-bounds offsets to the string boundary

substrmb_substriconv_substrgrapheme_substrが、範囲外の引数にも文字列を返すようになりました。

var_dump(substr('abc',10));// PHP8.0""// PHP7.4false

これまではfalseになっていました。

Populating $http_response_header variable by the HTTP stream wrapper doesn't force rebuilding of symbol table anymore

HTTPストリームラッパーが$http_response_headerを変更してもシンボルテーブルの再構築が行われなくなりました。

ということらしいけど内部のことはよくわかりません。
きっと詳しい人がなんか教えてくれるはず。

Sysvmsg

msg_get_queue() will now return an SysvMessageQueue object rather than a resource

msg_get_queueがリソースではなくSysvMessageQueueインスタンスを返すようになりました。

Sysvsem

sem_get() will now return an SysvSemaphore object rather than a resource

sem_getがリソースではなくSysvSemaphoreインスタンスを返すようになりました。

The $auto_release parameter of sem_get() was changed to accept bool values rather than int

sem_getの第4引数$auto_releaseの型がintからboolになりました。

Sysvshm

shm_attach() will now return an SysvSharedMemory object rather than a resource

shm_attachがリソースではなくSysvSharedMemoryインスタンスを返すようになりました。

tidy

The $use_include_path parameter has been removed from tidy_repair_string()

tidy_repair_stringの引数$use_include_pathが削除されました。

元々マニュアルにも載ってなかったんだけど、内部的に使っていたらしいです。

tidy::repairString() and tidy::repairFile() became static methods

tidy::repairStringtidy::repairFileが静的メソッドになりました。

tidy::repairString('hoge');// PHP8.0エラー出ない// PHP7.4Fatalerror:UncaughtError:Non-staticmethodtidy::repairString()cannotbecalledstatically

Tokenizer

T_COMMENT tokens will no longer include a trailing newline

T_COMMENTトークンは末尾の改行を含まなくなりました。

$str='<?php // comment
';var_dump(token_get_all($str)[1][1]);// PHP8.0string(10)"// comment"// PHP7.4string(11)"// comment
"

Namespaced names are now represented

名前空間はひとまとまりとして解釈されるようになりました。

// 出力は必要部分のみ$str='<?php
namespace FOO\BAR;
';var_dump(token_get_all($str));// PHP8.0[[T_NAME_RELATIVE,'FOO\BAR']]// PHP7.4[[T_STRING,'FOO'],[T_NS_SEPARATOR,'\'], [T_STRING, 'BAR']]

こちらのほうが名前空間としてわかりやすいですね。

XML

xml_parser_create(_ns) will now return an XmlParser object rather than a resource

xml_parser_createがリソースではなくXmlParserオブジェクトを返すようになりました。

$parser=xml_parser_create();xml_parse($parser,'<xml></xml>',true);var_dump($parser);// PHP8.0object(XmlParser)#1// PHP7.4resource(4)oftype(xml)

XMLパーサ関数は、これまでと同じ書き方で透過的に動作します。
またxml_parser_freeは実質的に何もしません。

XMLReader

XMLReader::open() and XMLReader::xml() are now static methods

XMLReader::openXMLReader::XMLは静的メソッドになりました。

XMLWriter

The XMLWriter functions now accept and return, respectively, XMLWriter objects instead of resources

XMLWriter::openUriなどがリソースではなくXMLWriterオブジェクトを返すようになりました。
XMLWriter関数は、これまでと同じ書き方で透過的に動作します。

Zip

ZipArchive::OPSYS_Z_CPM has been removed

定数ZipArchive::OPSYS_Z_CPMが削除されました。

echoZipArchive::OPSYS_Z_CPM;// PHP8.0Fatalerror:UncaughtError:UndefinedconstantZipArchive::OPSYS_Z_CPM// PHP7.49

これ、ZipArchive::OPSYS_CPMの誤字です。

Zlib

gzgetss() has been removed

gzgetssが削除されました。

inflate_init() will now return an InflateContext object rather than a resource

inflate_initがリソースではなくInflateContextオブジェクトを返すようになりました。
inflate_addなどは、これまでと同じ書き方で透過的に動作します。

deflate_init() will now return a DeflateContext object rather than a resource

deflate_initがリソースではなくDeflateContextオブジェクトを返すようになりました。
deflate_addなどは、これまでと同じ書き方で透過的に動作します。

zlib.output_compression is no longer automatically disabled for Content-Type: image/*

ini設定zlib.output_compressionは、これまでは画像に対しては自動的に無効化されていましたが、その自動無効化がなくなりました。

New Features

新機能。

この多くはPHP8.0の新機能で紹介しています。

Core

Added support for union types

UNION型が追加されました。

functionhoge(int|string$fuga):bool|stdClass{if($fuga===0){returntrue;}returnnewstdClass;}

関数hogeはint型もしくはstring型を受け取り、bool型もしくはstdClassインスタンスを返します。

Added WeakMap

弱いマップです。
メモリが足りなくなったら自動で削除されます。

Added ValueError class

ValueErrorクラスが追加されました。

echobcadd('1','2',-1);// PHP8.0Fatalerror:UncaughtValueError:bcadd():Argument#3 ($scale) must be between 0 and 2147483647// PHP7.43

bcaddの第三引数は小数点以下の桁数なので、マイナス値は不適切です。
このように、型は合っているけど値が範囲外のときに使われる例外となります。

Any number of function parameters may now be replaced by a variadic argument

継承時に、異なる型の値を可変長引数でまとめることができるようになりました。

classA{publicfunctionhoge(int$foo,string$bar,stdClass$baz){}}classBextendsA{publicfunctionhoge(...$args){}}// PHP8.0エラー出ない// PHP7.4Warning:DeclarationofB::hoge(...$args)shouldbecompatiblewithA::hoge

この場合、シグネチャは継承したクラスのものしか確認しません。
すなわち、(new B())->hoge(1, 2, 3)とか書いてもエラーは出ません。

これはいいのか??????

"static" (as in "late static binding") can now be used as a return type

返り値にstaticを書けるようになります。

classTest{publicfunctioncreate():static{returnnewstatic();}}

使い道がよくわからないので誰か解説よろ。

It is now possible to fetch the class name of an object using $object::class

インスタンスからクラス名を取得できるようになります。

echo(newstdClass)::class;// PHP8.0stdClass// PHP7.4Fatalerror:Cannotuse::classwithdynamicclassname

New and instanceof can now be used with arbitrary expressions

Some consistency fixes to variable syntax have been applied

デリファレンス可能範囲が拡大されます。

classFoo{constBAR='Bar';}classBar{publicstatic$baz='QUX';}echoFoo::BAR::$baz;// PHP8.0QUX// PHP7.4Parseerror:syntaxerror,unexpected'::'

これまでは構文エラーになっていたいくつかの構文が許されるようになります。
このRFCややこしくて正直理解が追い付いてません。

Added Stringable interface

Stringableインターフェイスが追加されました。

interfaceStringable{publicfunction__toString():string;}

これがあると__toString()可能になるというものですが、これは暗黙的にimplementsされるため、使用する側としては特に気にする必要はありません。

Traits can now define abstract private methods

traitでabstract privateメソッドが作成可能になりました。

traitFOO{abstractprivatefunctionbar();}// PHP8.0エラー出ない// PHP7.4Fatalerror:AbstractfunctionFOO::bar()cannotbedeclaredprivate

throw can now be used as an expression

throwが式になりました。

fn()=>thrownewException();// PHP8.0エラー出ない// PHP7.4Parseerror:syntaxerror,unexpected'throw'

構文の途中などで気軽に例外を投げられるようになります。

An optional trailing comma is now allowed in parameter lists

関数定義に末尾カンマが許可されました。

functionfoo($a,$b,){}// PHP8.0エラー出ない// PHP7.4Parseerror:syntaxerror,unexpected')'

関数を呼び出す方はPHP7.3から使えていたので、合わせた対応です。

It is now possible to write catch (Exception) to catch an exception without storing

例外の変数を明示的に受け取らないことができるようになりました。

try{newPDO();}catch(\Throwable){echo"なんかエラー出た";}// PHP8.0なんかエラー出た// PHP7.4Parseerror:syntaxerror,unexpected')'

PDOのエラーメッセージを表示すると脆弱性になる可能性があるので出したくない場合など、例外から来た値を使わずに処理したいという意図を明示できます。

Added support for mixed type

mixed型がサポートされました。

functionfoo(mixed$arg){}foo(1);foo('x');foo(newstdClass());// PHP8.0エラー出ない// PHP7.4UncaughtTypeError:Argument1passedtofoo()mustbeaninstanceofmixed,intgiven

マニュアルでは見慣れた型名ですね。
var_dumpの引数など、あえて多様な型を受け取りたいときに使います。

Added support for Attributes

アトリビュートが追加されました。

#[ExampleAttribute]functionfoo(){}

Javaでいうアノテーションです。
これまではPHPDocとかで適当に書いていましたが、これがPHPの構文としてパース可能な形で書けるようになります。

Added support for constructor property promotion

オブジェクト初期化子です。
素直にコンストラクタ引数昇格って言った方がわかりやすい気がしてきた。

classHOGE{publicfunction__construct(publicint$x){}}echo(newHOGE(99))->x;// PHP8.099// PHP7.4Parseerror:syntaxerror,unexpected'public'

コンストラクタ引数に可視性を書くと、自動的に同名のプロパティを作って値を突っ込んでくれます。
定型文をたくさん書く必要があって面倒だった初期化が楽になります。

コンストラクタ以外には使えません。

Added support for match expression

match式が導入されました。

echomatch("1"){1=>'1だ',true=>'trueだ',"1"=>'"1"だ',default=>'どれでもない',};// PHP8.0"1"// PHP7.4Parseerror:syntaxerror,unexpected'=>'

厳密な比較、フォールスルーしない、返り値を持つ式である、とswitch文の問題の多くを解消した構文です。

Private methods declared on a parent class no longer enforce any inheritance rules

privateメソッドが子クラスに影響しないようになりました。

classA{privatefinalfunctionfoo(int$arg){}}classBextendsA{privatefunctionfoo(string$agg){}}// PHP8.0Warning:Privatemethodscannotbefinal// PHP7.4Fatalerror:CannotoverridefinalmethodA::foo()

privateメソッドにfinalって書くと継承時に何故かFatal Errorになっていたのですが、これがオーバーライドチェックされないようになります。

かわりにprivateは上書きされないからfinalしなくていいというE_WARNINGが出るようになりました。

Added support for nullsafe operator

ヌル安全オペレータが追加されました。

echonull?->foo();// PHP8.0NULL// PHP7.4Parseerror:syntaxerror,unexpected'->'

ヌル安全オペレータ?->は、nullに対してプロパティやメソッドを取り出そうとすると、そこで処理が止まります。

なおnullでなければ止まらないので、(new stdClass)?->foo()とか書くとfoo()が無いってエラーになります。

Added support for named arguments

名前付き引数がサポートされました。

echohtmlspecialchars(encoding:'UTF-8',string:'>');// PHP8.0&gt;// PHP7.4Parseerror:syntaxerror,unexpected':'

引数の多い関数で最後の引数だけ呼んだり、引数の順番を入れ替えたりできます。
また呼び出し側に引数名を書くため、どの引数が何を表しているのか理解しやすくなります。

Date

Added DateTime::createFromInterface() and DateTimeImmutable::createFromInterface()

DateTime::createFromInterfaceDateTimeImmutable::createFromInterfaceが追加されました。

echo(DateTime::createFromInterface(newDateTimeImmutable()))->format('Y-m-d');// PHP8.02020-12-01// PHP7.4Fatalerror:UncaughtError:CalltoundefinedmethodDateTime::createFromInterface

名前からするとDateTime::createFromImmutableのように、DateTimeXXXからDateTimeを作るメソッドだと思われます。
現状ではDateTimeとDateTimeImmutableしかないうえにDateTimeInterfaceをユーザがimplementsすることはできないので意味はありませんが、将来種類が増えたときに役立ちそうです。

Added the DateTime format specifier "p"

DateTimeのフォーマットpが追加されました。
Pと同じですが、+00:00のときだけZが返ります。よくわからない。

Dom

Introduce DOMParentNode and DOMChildNode

DOMParentNode、DOMChildNodeが追加されました。
普段SimpleXMLしか使わないからよくわからない。

Enchant

enchant_dict_add / enchant_dict_is_added

enchant_dict_addenchant_dict_is_addedが追加されました。

Enchantを実用で使ってる人っているんだろうか。

FPM

Added a new option pm.status_listen

設定pm.status_listenが追加されました。
異なるエンドポイントのステータスを確認できるとかなんとか。

Hash

HashContext objects can now be serialized

HashContextがシリアライズ可能になりました。

echoserialize(hash_init('md5'));// PHP8.0O:11:"HashContext":5// PHP7.4Fatalerror:UncaughtException:Serializationof'HashContext'isnotallowed

リクエストを超えてハッシュ作成を継続したいとかあるのか?

Opcache

If the opcache.record_warnings ini setting is enabled, opcache will record compile-time warnings

ini設定opcache.record_warningsを有効にした場合、コンパイル時に発生した警告をして次のアクセス時にも発生させます。

OpenSSL

Added Cryptographic Message Syntax (CMS)

Cryptographic Message Syntaxがサポートされました。

Standard

printf() and friends now support the %h and %H format specifiers

printfおよび類似関数が、指定子%h%Hをサポートしました。
%g%Gと同じですが、ロケールに関わらず小数点が.になります。

setlocale(LC_ALL,'fr');echosprintf('%g - %h',1.2,3.4);// PHP8.01,2-// PHP7.41,2-3.4

上の方にもあったフランス語問題の対応です。

printf() and friends now support using "*" as width or precision

printfおよび類似関数が、量指定子*をサポートしました。

printf("%.*f",10,1.2);// PHP8.01.2000000000// PHP7.4f

精度を外側から渡すことができます。
これまでも文字列結合などで実現は可能でしたが、簡単に書けるようになります。

proc_open() now supports pseudo-terminal (PTY) descriptors

proc_openが疑似ターミナルをサポートしました。

$proc=proc_open('dir',[['pty'],['pty'],['pty']],$pipes);// PHP8.0Warning:proc_open():PTY(pseudoterminal)notsupportedonthissystem// PHP7.4Warning:proc_open():ptypseudoterminalnotsupportedonthissystem

なんにしろWindowsではサポートされてなかった。

proc_open() now supports socket pair descriptors

proc_openがソケットをサポートしました。

$proc=proc_open('dir',[['socket'],['socket'],['socket']],$pipes);// PHP8.0エラー出ない// PHP7.4Warning:proc_open():socketisnotavaliddescriptorspec/mode

こちらはWindowsでも使えます。

Sorting functions are now stable

ソート関数が安定ソートになりました。

$array=['a'=>1,'b'=>1,];asort($array);

これまではソート後にaとbの位置がどうなっているか保証がなかったのですが、今後はaとbの順番が保たれます。

array_diff(), array_intersect() and their variations can now be used with a single array as argument

array_diffなどを引数ひとつで使えるようになりました。

array_diff([1,2]);// PHP8.0エラー出ない// PHP7.4Warning:array_diff():atleast2parametersarerequired,1given

単独だと意味はないですが、array_intersect(...$arrays)のように展開して渡したいときに役立ちます。

The $flag parameter of ob_implicit_flush() was changed to accept bool values

ob_implicit_flushの引数$flagがbool型になりました。

Zip

Extension updated to version 1.19.1

zipエクステンションのバージョンが1.19.1になりました。
と言われてもこれがlibzipのことかすらよくわからないのですが。

New ZipArchive::lastId property

ZipArchiveにlastIdプロパティが追加されました。
最後に追加したファイルのインデックスです。

Error can be checked after an archive is closed

ZipArchiveを閉じた後でも、ZipArchive::statusなどでステータスを確認可能になりました。

The remove_path option of ZipArchive::addGlob() and ::addPattern() is now treated as arbitrary string prefix

ZipArchive::addGlobおよびZipArchive::addPatternのオプションremove_pathは、アーカイブを追加する際に削除される接頭辞になりました。
以前はディレクトリ名でしたが、add_pathと整合が取れていなかったので変更されました。

Optional compression / encryption features are listed in phpinfo

圧縮/暗号化オプションがphpinfoに表示されるようになりました。

Changes in SAPI modules

SAPIモジュールへの変更

Apache

The PHP module has been renamed

Apache PHPモジュールの名前がphp7_moduleからphp_moduleに変更されました。

今後メジャーバージョンアップのたびにLoadModule php8_moduleとか書き替えずに済むようになります。

Deprecated Functionality

非推奨になる機能。
ここで『できなくなった』と書いてあるのは非推奨と読み替えてください。

Core

Declaring a required parameter after an optional one is deprecated

省略可能引数の後で必須引数を記述することができなくなりました。

functionhoge($foo='foo',$bar){}// PHP8.0Deprecated:Requiredparameter$barfollowsoptionalparameter$foo// PHP7.4エラー出ない

今まで許可されていたことにびっくりですね。

Calling get_defined_functions() with $exclude_disabled explicitly set to false is deprecated

get_defined_functionsの引数$exclude_disabledにfalse指定ができなくなりました。

互換性のない変更点において、無効化された関数は存在しないものにされました。
そのため、このフラグには意味がなくなりました。

Enchant

enchant_broker_set_dict_path and enchant_broker_get_dict_path not available

libenchant-2では、enchant_broker_set_dict_pathenchant_broker_get_dict_pathが使えなくなりました。

enchant_dict_add_to_personal, use enchant_dict_add instead

enchant_dict_add_to_personalが非推奨になりました。
かわりにenchant_dict_addを使います。

enchant_dict_is_in_session, use enchant_dict_is_added instead

enchant_dict_is_in_sessionが非推奨になりました。
かわりにenchant_dict_is_addedを使います。

enchant_broker_free and enchant_broker_free_dict, unset the object instead

enchant_broker_freeenchant_broker_free_dictが非推奨になりました。
かわりにunsetを使います。

ENCHANT_MYSPELL and ENCHANT_ISPELL constants

定数が非推奨になりました。

LibXML

libxml_disable_entity_loader() has been deprecated

libxml_disable_entity_loaderが非推奨になりました。
XXE脆弱性対応のためです。

PGSQL / PDO PGSQL

The constant PG_VERSION_STR has now the same value as PG_VERSION, and thus is deprecated

定数PG_VERSION_STRは中身がPG_VERSIONと同じになり、さらに非推奨になりました。

PG_VERSION_STRもPG_VERSIONもPostgresの項目ににないんだけど何処で定義されてるんだろう。

Function aliases in the pgsql extension have been deprecated

Postgres関数の古い呼び名のエイリアスが非推奨になりました。

たとえばpg_lo_openにはpg_loopenというエイリアスが存在し、PHP7.4までは警告なく使用可能でした。

Zip

Using empty file as ZipArchive is deprecated

空のファイルをZipArchiveとして扱うことができなくなりました。
libzip 1.6.0で非対応になったためです。

The procedural API of Zip is deprecated

手続き型のzip関数は非推奨になりました。

zip_open('tmp');// PHP8.0Deprecated:Functionzip_open()isdeprecated// PHP7.4エラー出ない

ZipArchiveを使いましょう。

Reflection

ReflectionFunction::isDisabled() is deprecated

ReflectionFunction::isDisabledが非推奨になりました。
無効化された関数は存在しないものにされたためです。

ReflectionParameter::getClass(), ReflectionParameter::isArray(), and ReflectionParameter::isCallable() are deprecated

ReflectionParameter::getClassReflectionParameter::isArrayReflectionParameter::isCallableが非推奨になりました。

かわりにReflectionParameter::getTypeReflectionTypeを使いましょう。

Changed Functions

仕様が変更になる関数。

Reflection

ReflectionClass::getConstants and ReflectionClass::getReflectionConstants results can be now filtered

https://www.php.net/manual/ja/reflectionclass.getconstantsReflectionClass::getReflectionConstantsに引数$filterが追加されました。
またフィルタ用の定数ReflectionClassConstant::[IS_PUBLIC|IS_PROTECTED|IS_PRIVATE]が追加されました。

classFOO{publicconstA='A';protectedconstB='B';privateconstC='C';}$c=(newReflectionClass('FOO'))->getReflectionConstants(filter:ReflectionClassConstant::IS_PRIVATE);// privateの定数Cだけ出てくる

引数未指定のときはこれまでどおり全て出てきます。

Zip

ZipArchive::addGlob and ZipArchive::addPattern methods accept more values in the "options"

ZipArchive::addGlobZipArchive::addPatternの引数$optionsに対象が追加されました。

  • flags
  • comp_method
  • comp_flags
  • env_method
  • enc_password

ZipArchive::addEmptyDir, ZipArchive::addFile and aZipArchive::addFromString methods have a new "flags" argument

ZipArchive::addEmptyDirZipArchive::addFileZipArchive::addFromStringに引数$flagsが追加されました。

ZipArchive::extractTo now restore file modification time

ZipArchive::extractToがmtimeを復元するようになりました。
これまでは解凍した時刻になっていました。

New Functions

新しい関数。

Core

Added get_resource_id($resource) function

関数get_resource_idが追加されました。

echoget_resource_id(tmpfile());// 4 環境によって変わる

リソースのリソースIDを取得できます。
(int)$resourceと同じですが、関数的に記述することができます。

ldap_count_references

関数ldap_count_referencesが追加されました。

よくわかりませんが、おそらくWindowsAPIなどと同じものでしょう。
他のLDAP関数ほぼ共通ですし。

OpenSSL

Added openssl_cms_encrypt() / openssl_cms_decrypt() / openssl_cms_read() / openssl_cms_sign() / openssl_cms_verify()

CMS関連の関数が追加されました。
Cryptographic Message Syntaxサポートに伴い導入されたものです。

openssl_cms_encrypt('input.txt','output.txt',file_get_contents('key.pem'),[]);

使い方はopenssl_pkcs7_XXXXXと相似です。

PCRE

Added preg_last_error_msg

preg_last_error_msgが追加されました。

preg_match('/(?:\D+|<\d+>)*[!?]/','foobar foobar foobar');echopreg_last_error_msg();// Backtrack limit exhausted

正規表現で最後に発生したエラーメッセージを返します。
意味的にはpreg_last_errorと同じですが、こちらはintでわかりにくいため、メッセージとして出力するようにしたものです。

SQLite3

Add SQLite3::setAuthorizer() and respective class constants

SQLite3::setAuthorizerが追加されました。

SQLを実行するたびに呼ばれるコールバックを設定することができます。

Standard

str_contains / str_starts_with / str_ends_with

str_containsstr_starts_withstr_ends_withが追加されました。

str_contains('森久保乃々','森久保');// truestr_starts_with('望月聖','望月');// truestr_ends_with('イヴ・サンタクロース','サンタクロース');// true

それぞれ○○が含まれる○○で始まる/終わる、の文字列検索を楽にする関数です。

Added fdiv() function

fdivが追加されました。

echofdiv(1,0);// INF

IEEE 754に準拠した割り算です。

Added get_debug_type() function

get_debug_typeが追加されました。

echoget_debug_type(1),get_debug_type(newDateTime());// int, DateTime

プリミティブ型の型名を返すgettypeと、オブジェクトのクラス名を返すget_class悪魔合体です。

Zip

ZipArchive::setMtimeName and ZipArchive::setMtimeIndex

ZipArchive::setMtimeNameZipArchive::setMtimeIndexが追加されました。
mtimeを操作できます。

ZipArchive::setProgressCallback / ZipArchive::setCancelCallback

ZipArchive::setProgressCallbackとZipArchive::setCancelCallbackが追加されました。

ってUPGRADINGには書いてあるんだけど、試してみるとCall to undefinedって言われるしregisterProgressCallbackregisterCancelCallbackが存在するのでおそらく間違い。

ZipArchive::replaceFile

ZipArchive::replaceFileが追加されました。
中身のファイルの一部を置き換えるみたいだけど、そんなややこしいことをPHPで行うことはあるのだろうか。

ZipArchive::isCompressionMethodSupported / ZipArchive::isEncryptionMethodSupported

ZipArchive::isCompressionMethodSupportedZipArchive::isEncryptionMethodSupportedが追加されました。

名前のとおり、圧縮方式および暗号化方式をサポートしているか確認できます。

New Classes and Interfaces

新しいクラス、インターフェイス。

Tokenizer

PhpToken

PhpTokenクラスが追加されました。

echo PhpToken::tokenize('<?php echo; ?>')[0]->text; // <?php

既存のTokenizerをオブジェクト的に扱えるようにしたものです。

Removed Extensions and SAPIs

削除されたエクステンション、SAPIなど。

XML-RPC

The xmlrpc extension has been unbundled and moved to PECL

XML-RPCがPHPコアから削除され、PECL行きになりました。
内部で使っているxmlrpc-epi開発放棄されているためです。

Other Changes to Extensions

そのほかの変更点。

CURL

The CURL extension now requires at least libcurl 7.29.0

Curlエクステンションがlibcurlの7.29.0以上を必要とするようになりました。

curl_init() will now return a CurlHandle object rather than a resource

curl_initはリソースではなくCurlHandleオブジェクトを返すようになりました。

var_dump(curl_init());// PHP8.0object(CurlHandle)#1// PHP7.4resource(4)oftype(curl)

他のCurl関数はこれまでと同じ書き方で透過的に動作します。
curl_closeは実質的に何もしなくなりました。

curl_multi_init() will now return a CurlMultiHandle object rather than a resource

curl_multi_initはリソースではなくCurlMultiHandleオブジェクトを返すようになりました。

それ以外はcurl_initとほぼ同じです。

curl_share_init() will now return a CurlShareHandle object rather than a resource

curl_share_initはリソースではなくCurlShareHandleオブジェクトを返すようになりました。

それ以外はcurl_initとほぼ同じです。

The deprecated parameter $version of curl_version() has been removed

非推奨だったcurl_versionの第一引数$versionが削除されました。

マニュアルからは既に抹消されています。

Date

DatePeriod now implements IteratorAggregate

DatePeriodIteratorAggregateをimplementsするようになりました。

(newReflectionClass('DatePeriod'))->getInterfaceNames();// [IteratorAggregate, Traversable]

以前はTraversableでした。

DOM

DOMNamedNodeMap / DOMNodeList now implements IteratorAggregate

DOMNamedNodeMapおよびDOMNodeListIteratorAggregateをimplementsするようになりました。
これらも以前はTraversableでした。

Intl

IntlBreakIterator / ResourceBundle now implements IteratorAggregate

IntlBreakIteratorおよびResourceBundleIteratorAggregateをimplementsするようになりました。
以前はTraversableでした。

Enchant

The enchant extension now uses libenchant-2 by default when available

Enchantエクステンションが使用しているlibenchantのバージョンがlibenchant-2になりました。
1系は非推奨となり、将来的に削除されます。

GD

The $num_points parameter of imagepolygon(), imageopenpolygon() and imagefilledpolygon() is now optional

imagepolygonimageopenpolygonimagefilledpolygonの引数$num_pointsが省略可能になりました。
省略した場合、$points / 2とみなされます。

imagepolygon($im=imagecreatetruecolor(100,100),[1,2,3,4,5,6],imagecolorallocate($im,255,255,255))

第四引数$colorは省略不可のため、省略する場合は第三引数に$colorを入れる、すなわち引数の数によって第三引数の意味が変わるという非常にわかりにくいことになります。
負債を増やしてどうする。

imagepolygon($im=imagecreatetruecolor(100,100),[1,2,3,4,5,6],null,imagecolorallocate($im,255,255,255));// Fatal error:  Uncaught ValueError: imagepolygon(): Argument #3 ($num_points_or_color) must be greater than or equal to 3imagepolygon($im=imagecreatetruecolor(100,100),points:[1,2,3,4,5,6],color:imagecolorallocate($im,255,255,255))// Fatal error:  Uncaught ArgumentCountError: imagepolygon(): Argument #3 ($num_points_or_color) not passed

nullにしたり名前付き引数で飛ばしたりといったこともできません。
これはもっとどうにかしたほうがよかったのでは。

The function imagegetinterpolation() to get the current interpolation method has been added

imagegetinterpolationが追加されました。

$im=imagecreatetruecolor(100,100);imagesetinterpolation($im,IMG_GENERALIZED_CUBIC);echoimagegetinterpolation($im);// 11

現在設定されている補間方法を取得します。

JSON

The JSON extension cannot be disabled anymore

JSONエクステンションを無効にすることができなくなりました。

マニュアルには全く載っていないのですが、実はこれまでコンパイルオプション--disable-jsonで無効化することが可能でした。

MBString

The Unicode data tables have been updated to version 13.0.0

Unicodeデータベースが13.0.0にバージョンアップされました。

PDO

PDOStatement now implements IteratorAggregate

PDOStatementIteratorAggregateをimplementsするようになりました。
以前はTraversableでした。

LibXML

The minimum required libxml version is now 2.9.0

要求するlibxmlがバージョン2.9.0以上になりました。

以前は2.6.0以上でした。

MySQLi / PDO MySQL

When mysqlnd is not used the minimum supported libmysqlclient version is now 5.5

要求するlibmysqlclientのバージョンが5.5以上になりました。
libmysqlclientではなくmysqlndを使う場合は不要です。

ところでマニュアルには『mysqlndを勧める』って書いてあるんだけど、変更履歴では『libmysqlclientが推奨だしデフォルトもこっち』って書いてあるんですよね。
どっちが正解なんだ。

mysqli_result now implements IteratorAggregate

mysqli_resultIteratorAggregateをimplementsするようになりました。
以前はTraversableでした。

PGSQL / PDO PGSQL

The PGSQL and PDO PGSQL extensions now require at least libpq 9.1

要求するlibpqのバージョンが9.1以上になりました。

Readline

Calling readline_completion_function() before the interactive prompt starts will now override the default interactive prompt completion function

readline_completion_functionは、対話型シェルが起動していないときにも動くようになりました。
以前は、既に対話型シェルが起動していないと動きませんでした。

SimpleXML

SimpleXMLElement now implements RecursiveIterator and absorbed the functionality of SimpleXMLIterator

SimpleXMLElementRecursiveIteratorをimplementsするようになりました。
以前はTraversableでした。

さらにSimpleXMLIteratorの機能を吸収しました。
SimpleXMLIteratorは実質的にSimpleXMLElementと同じになりました。

Shmop

shmop_open() will now return a Shmop object rather than a resource

shmop_openはリソースではなくShmopオブジェクトを返すようになりました。

他の共有メモリ関数はこれまでと同じ書き方で透過的に動作します。
shmop_closeは実質的に何もしなくなります。

New Global Constants

新たなグローバル定数。

Filter

FILTER_VALIDATE_BOOL has been added as an alias for FILTER_VALIDATE_BOOLEAN

検証フィルタFILTER_VALIDATE_BOOLが追加されました。

var_dump(FILTER_VALIDATE_BOOL,FILTER_VALIDATE_BOOLEAN);// 258, 258

これはFILTER_VALIDATE_BOOLEANのエイリアスです。
真偽型の表記はboolに揃えられつつあるので、他のbooleanもいずれboolに変更されるでしょう。

Changes to INI File Handling

iniファイルの変更。

zend.exception_string_param_max_len

ini設定zend.exception_string_param_max_len追加されました
スタックトレースに表示される引数の文字数を制御します。

try{substr('12345678901234567890');}catch(Throwable$e){echo$e->getTraceAsString();}// zend.exception_string_param_max_len=15のとき#0 C:\xampp\htdocs\test.php(10): substr('123456789012345...')// zend.exception_string_param_max_len=1のとき#0 C:\xampp\htdocs\test.php(6): substr('1...')

開発時のデバッグなどに重宝するでしょう。

デフォルトは15で、範囲は0から1000000です。
ini_setで変更できたのでPHP_INI_ALLのようです。

com.dotnet_version

dotnetを使う際の.netフレームワークのバージョンを指定できるようです。

Windows Support

Standard

Program execution functions using the shell now consistently execute %comspec% /s /c "$commandline",

execなどのシェルコマンド実行関数が、一貫して%comspec% /s /c "$commandline"という形で実行されるようになりました。

ということらしいですがよくわかりません。

GD

php_gd2.dll has been renamed to php_gd.dll

GDエクステンションのファイル名がphp_gd2.dllからphp_gd.dllに変更されました。

php-test-pack

The test runner has been renamed from run-test.php to run-tests.php

テストパッケージのテストランナーファイル名がrun-test.phpからrun-tests.phpに変更されました。

Other Changes

その他の変更点

EBCDIC targets are no longer supported

文字コードEBCDICがサポート対象外になりました。

果たして使っていた人はいるのだろうか?

Performance Improvements

パフォーマンスについて。

A Just-In-Time (JIT) compiler has been added to the opcache extension

JITがサポートされました。

functiongetFibonacci(int$i){return$i<2?$i:getFibonacci($i-1)+getFibonacci($i-2);}$a=microtime(true);echogetFibonacci(38);$b=microtime(true);echo$b-$a;
PHP8デフォルトopcache有効JIT有効
6.9316395.8339151.698887
7.4431455.5366122.009317
6.6107695.6193381.662739
6.7945685.6541121.739347
7.2861945.7742231.788053

CPUバウンドな処理はとんでもない速さになります。

ただPHPの主な用途はディスクやデータベースへのIOで、それらにはJITの恩恵はほぼないので、実際のWebアプリケーションはここまで極端に速くはなりません。
公式LPではざっくり1割から3割減というところですね。
02.png

感想

変更点多すぎ!!!!
PHP8たいしたことないんじゃねえのとか言ってた奴土下座な。

互換性のない変更の多くは、古くからのアバウトな仕様を排除し、厳密な書き方を推奨する方向に向けるものです。
implodeの引数が逆順でも書けるなんてのはその最たるものですね。
そのぶん昔からの熟成されたソースを使っているところは移行が大変になると思いますが、PHPは互換を切ってでも進化し続ける方向を選んだということなので、まあがんばってもらいましょう。
それにPHP7以降の近代風な書き方をしている限りでは、変更が必要なところはほとんどありません。

そして新機能については、流行りの書式やら文法などを貪欲に取り入れていて、このあたりはさすがPHPってところです。
節操がないとも言えますが、その節操のなさこそがPHPたる所以と言えましょう。
アロー関数や型宣言、アトリビュートあたりはまだ機能が半端なので、次のメジャーバージョンかあるいはマイナーバージョンでさらに進化しそうですね。

さらにJITが入ったことで、Webアプリケーションだけに囚われない、実用的な計算ライブラリでもPHPが輝く時代がやってくるかもしれません。
まあC++やGoあたりとはさすがに比べものにはならないですが、他のスクリプト言語に比べればだいぶいい線行っているのではないでしょうか。

Qiitaのトレンド表示が改悪された

$
0
0

2020/11/30あたりにQiitaトップページのレイアウトが変更されました。

  • トレンドにNewの表示が出なくなった。
  • 訪問済リンクの色が変わらなくなった。

結果として、その記事を既に閲覧したかどうかが全く判別できない。

a.png

なんで:visited入れてくれないの???

あとLGTMだけで1行取るのってわりと無駄な気がする。

解決策

Stylusとかに↓のCSSを突っ込めばいいです。

.css-81mxb5a:visited{color:#f00;}

css-81mxb5とかは自動生成と思われるのでいつまでも使えるかは怪しいですが、idはHomeArticleTrendFeed-react-component-433a141c-64f3-4ee8-bf53-e3dce809f355とかなのでさらに役立ちそうにない。
誰かがもっとちゃんとしたセレクタを書いてくれるはず。

02.png

※SS撮影のため履歴を全消しした

【PHP8】PHPに代数的データ型ほしくない? よし、まずは列挙型だ

$
0
0

PHPの開発者のひとり、Larry GarfieldがMLに列挙型のRFCを投稿しました。

最近Ilija ToviloとふたりでPHPに代数的データ型のサポートを追加する作業を行ってるよ。
このプロジェクトは何段階かあるんだけど、まずは第一段階として列挙型を公開レビューするよ。

MLとプルリクで幾つかの突っ込みと修正が入っています。
しかし全体としては多くが賛成となっており、致命的な問題でも見つからないかぎり導入される可能性は高いでしょう。

ということで以下はPHP RFC: Enumerationsの日本語訳です。

PHP RFC: Enumerations

Introduction

このRFCは、PHPに列挙型を導入するものです。
このRFCの範囲は列挙型のみに限定されています。
すなわちプリミティブ型の糖衣構文などはなく、列挙型に関連する事項以外の追加情報は含まないようにしています。

列挙型の機能により、データモデリング、カスタム型の定義、モナドスタイルのサポートなどが大幅に拡充されるでしょう。
列挙型は、「無効な状態は存在できないようにする」というモデリングを可能とし、不要なテスト工数を減らし、より堅牢なコードを記述できるようになります。

多くの言語は、複数種類の列挙型をサポートしています。
複数言語を調査した結果によると、一般的に3つのグループに分類できることがわかりました。
すなわちファンシーな定数、ファンシーなオブジェクト、そして完全な代数的データ型です。

このRFCは、完全な代数的データ型を導入するという大きな取り組みの一部です。
従ってこのRFCでは、今後のRFCで完全な代数的データ型に拡張できるように、"ファンシーなオブジェクト"タイプのENUMを実装します。
これはSwift、Rust、Kotlinなどの考え方の影響を受けていますが、それらを直接的にモデル化したわけではありません。

列挙型の値のもっとも一般的なケースは真偽型で、取ることのできる値はtruefalseのみです。
このRFCでは、開発者が独自に任意の列挙型を定義することが可能にしています。

Proposal

列挙型は、クラスとオブジェクトを下敷きに構築されています。
すなわち、特に断りのない限り「この場合の列挙型の動作はどうなるの?」は、「オブジェクトのインスタンスと同じ」となります。
たとえばオブジェクト型チェックに成功し、大文字小文字を区別しません(オートロード時の区別がファイルシステム・クラスローダ依存なのも同じ)。

Unit enumerations

このRFCでは、enumという新しい言語機能が導入されます。
Enumはクラスに似ており、クラス・インターフェイス・トレイトと同じ名前空間に存在します。
また同じようにオートロードも可能です。
列挙型は、限られた数の有効な値を持ちます。

enumSuit{caseHearts;caseDiamonds;caseClubs;caseSpades;}

この構文では、4つの値を持つ新たな列挙型Suitを作成しました。
値とはすなわちSuit::HeartsSuit::DiamondsSuit::ClubsSuit::Spadesです。
これら4値を変数などに代入することができます。
型宣言に列挙型を指定した場合は、その型の値のみを渡すことができます。

$val=Suit::Diamonds;functionpick_a_card(Suit$suit){...}pick_a_card($val);// OKpick_a_card(Suit::Clubs);// OKpick_a_card('Spades');// TypeError

列挙型は0個以上のcaseを持つことができ、上限はありません。
caseが0個の列挙型は構文的には有効ですが、実質的にあまり意味がありません。

caseは具体的なスカラー値に紐付けられているわけではありません。
それぞれのcaseは紐付けられているシングルトンと等しくなります。

$a=Suit::Spades;$b=Suit::Spades;$a===$b;// true$ainstanceofSuit;// true$ainstanceofSuit::Spades;// true

このタイプの列挙型(caseのみでできていて、関連データなどは付けられない)はユニット列挙型として知られています。

これはEnumインターフェイスを実装するオブジェクトとして実装されており、また内部インターフェイスUnitEnumも実装しています。
他のオブジェクトと列挙型を区別する方法のひとつです。

Suit::HeartsinstanceofEnum;// trueSuit::HeartsinstanceofUnitEnum;// true

Enumerated Case Methods

列挙型もクラスなので、メソッドを定義することができます。

またインターフェイスをimplementsすることもできますが、その場合は全てのcaseに対して実装しなければなりません。
個々のcaseにインターフェイスをimplementsすることはできません。

interfaceColorful{publicfunctioncolor():string;}enumSuitimplementsColorful{caseHearts{publicfunctioncolor():string{return"Red";}}caseDiamonds{publicfunctioncolor():string{return"Red";}}caseClubs{publicfunctioncolor():string{return"Black";}}caseSpades{publicfunctioncolor():string{return"Black";}}publicfunctionshape():string{return"Rectangle";}}functionpaint(Colorful$c){...}paint(Suit::Clubs);// Works

この例では、4つのcaseは全てSuiteから継承したメソッドcolorを持っています。
case内のメソッドは他のメソッドと同じように動作します。

またcase内では$thisが定義されていて、Caseインスタンスを参照することができます。

上記の場合、RedBlackの値を持つSuitColor列挙型を定義して、それを返す方がよりよいモデリングになるでしょう。
ただそうすると例が複雑になってしまうため避けました。

上記の列挙型は、下記のように書き替えることもできます。

interfaceColorful{publicfunctioncolor():string;}abstractclassSuitimplementsUnitEnum,Colorful{publicfunctionshape():string{return"Rectangle";}publicfunctioncases():array{// See below.}}classHeartsextendsSuit{publicfunctioncolor():string{return"Red";}}classDiamondsextendsSuit{publicfunctioncolor():string{return"Red";}}classClubsextendsSuit{publicfunctioncolor():string{return"Black";}}classSpadesextendsSuit{publicfunctioncolor():string{return"Black";}}

列挙型に静的メソッドを持たせ、各caseは静的メソッドを持たないことができます。

列挙型に静的メソッドを持たせる理由は、主に代替コンストラクタのためです。
たとえば以下のような記述が可能です。

enumSize{caseSmall;caseMedium;caseLarge;publicstaticfunctionfromLength(int$cm){returnmatch(true){$cm<50=>static::Small,$cm<100=>static::Medium,default=>static::Large,};}}

Comparison to objects

列挙型は内部的にはクラスを使って実装されていて、セマンティクスの多くを共有しています。
ただし幾つかのオブジェクトスタイルの機能は禁止されています。
これらの機能は列挙型においては意味がないか、不明瞭であるか、あるいは議論の余地がある(今後追加される可能性がある)ものです。

  • コンストラクタ・デストラクタ:状態を持たせなければ不要です。
  • 継承:列挙型は設計上クローズドであり、継承は列挙型を壊します。
  • 定数:メソッドを使います。
  • プロパティ:状態を持たせません。
  • 動的プロパティ:良い設計ではありません。
  • マジックメソッド:別途記載する一部を除き使用できません。
  • シリアライズ:シリアライズはできません。

これらの機能が必要であれば、既存のクラスの方が優れた選択肢になります。

以下のオブジェクトの機能は利用可能です。

  • メソッドのpublic / protected / privateアクセス修飾子
  • マジックメソッド__get__call__invoke
  • 定数__CLASS____FUNCTIONS__

列挙型へのマジック定数::classはオブジェクトと全く同じ、名前空間を含む型名で評価されます。

caseへのマジック定数::classは、::のついた値で評価されます。
たとえばFoo\Bar\Baz\Suit::Spadesです。

静的メソッドはcaseには使えず、列挙型自体には使用可能です。

また、各casenewで直接インスタンス化することはできず、newInstanceWithoutConstructorなどのリフレクションでインスタンス化することもできません。

Scalar Enums

デフォルトでは、列挙されたcaseに等しいスカラ値は存在しません。
単なるシングルトンオブジェクトです。
しかし列挙型の値を他のデータベースなどにストアする可能性は高いので、シリアライズ可能なスカラ値が存在すると便利です。

以下の構文で、列挙型にスカラ値を定義することができます。

enumSuit:string{caseHearts='H';caseDiamonds='D';caseClubs='C';caseSpades='S';}

スカラ値の型はintもしくはstringであり、ひとつの列挙型は単一の型のみをサポートします。
つまりint|stringのユニオン型はサポートされません。
列挙型がスカラ値を持つ場合は、全てのcaseは一意でなければならず、同じ値を持つことはできません。
自動インクリメントなどの自動生成スカラ値は存在しません。

スカラ列挙型の値をスカラコンテキストで使用する場合、自動的にスカラ値にダウンキャストされます。
たとえばprintの引数に渡すとスカラ値として評価されます。

printSuit::Clubs;// "C"print"I hope I draw a ".Suit::Spades;// "I hope I draw a S".

スカラ列挙型は内部インターフェイスUnitEnumにくわえてScalarEnumインターフェイスも実装されており、ScalarEnumインターフェイスにはfrom()メソッドが定義されています。
このメソッドはスカラ値から対応するcaseを返します。
一致するcaseが存在しない場合はValueErrorをthrowします。

$record=get_stuff_from_database($id);print$record['suit'];// "H"$suit=Suit::from($record['suit']);$suit===Suit::Hearts;// true

スカラ列挙型も、ユニット列挙型同様メソッドを持つことができます。

enumSuit:string{caseHearts='H';caseDiamonds='D';caseClubs='C';caseSpades='S'{publicfunctioncolor():string{return'Black';}}publicfunctioncolor():string{// ...}}

Value listing

UnitEnumインターフェイスには静的メソッドcases()が実装されています。
このメソッドは、定義された全てのcaseを順に返します。

Suit::cases();// [Suit::Hearts, Suit::Diamonds, Suit::Clubs, Suit:Spades]

スカラ列挙型でない場合は0から順にインデックスがつけられます。
スカラ列挙型の場合は、対応するスカラ値がキーになります。

またScalarEnumインターフェイスには、スカラ値を返すvalue()メソッドが実装されています。

'D'==Suit::Diamonds->value();// true

Attributes

列挙型と各caseには、他の言語要素と同じくアトリビュートを適用可能です。
Attributeクラスにふたつのターゲット定数が追加されます。
TARGET_ENUMは列挙型自体を対象とし、TARGET_CASEcaseを対象とします。

言語が定義するアトリビュートはありません。
ユーザ定義のアトリビュートでは何でもできます。

Match expressions

列挙値に応じてロジックを分岐させる方法として、match式が便利な文法を提供します。

$val=Suit::Diamonds;$str=match($val){Suit::Spades=>"The swords of a soldier",Suit::Clubs=>"Weapons of war",Suit::Diamonds=>"Money for this art",default=>"The shape of my heart",}

match式の自然な使い方であり、matchの構文に手を加える必要はありません。

Reflection

列挙型のリフレクションは、ReflectionClassをextendsしたReflectionEnumクラスを使用します。
無関係なメソッド、getProperty()などは常に空の値を返します。
また、以下のメソッドが追加されます。

  • hasCase(string $name): boolそのcaseを持っていればtrueを返す。$r->hasCase('Hearts')はtrue。
  • getCases(): array ReflectionCaseの配列を返す。
  • getCase(string $name): ReflectionCaseその名前のReflectionCaseを返す。
  • hasType(): boolスカラ列挙型であればtrueを返す。
  • getType(): ReflectionTypeスカラ列挙型であればその型を、そうでなければ空のReflectionTypeを返す。

ReflectionCaseは、列挙型の中の個々のcaseを表します。
これもReflectionClassをextendsしており、以下のメソッドが追加されます。

  • getEnum(): ReflectionEnum caseの入っている列挙型のReflectionEnumを返す。
  • getScalar(): ?int|stringスカラ列挙型であればその値を、そうでなければnullを返す。
  • getInstance(): Enum該当の列挙型インスタンスを返す。

Examples

以下に、列挙型の例をいくつか表示します。

Basic limited values

enumSortOrder{caseASC;caseDESC;}functionquery($fields,$filter,SortOrder$order){...}

query関数は、引数$orderSortOrder::ASCもしくはSortOrder::DESCのいずれかであることを保証できるようになりました。
それ以外の値を指定するとTypeErrorが発生するため、これ以上のチェックやテストは必要ありません。

Advanced Exclusive values

enumUserStatus:string{casePending='pending'{publicfunctionlabel():string{return'Pending';}}caseActive='active'{publicfunctionlabel():string{return'Active';}}caseSuspended='suspended'{publicfunctionlabel():string{return'Suspended';}}caseCanceledByUser='canceled'{publicfunctionlabel():string{return'Canceled by user';}}}

ユーザのステータスはUserStatus::PendingUserStatus::ActiveUserStatus::SuspendedUserStatus::CanceledByUserのいずれかであり、他の値を取ることはできません。

これら4値はポリモーフィックなlabel()メソッドを持っており、これは人間に読める文字列を返します。
この値はデータベースやHTMLのselectボックスに入れる値とは独立して指定することができます。

foreach(UserStatus::cases()as$key=>$val){printf('<option value="%s">%s</option>\n',$key,$val->label());}

label()メソッドは個別に実装せず、ひとつのメソッドとして列挙型クラスに実装することもできます。

enumUserStatus:string{casePending='pending';caseActive='active';caseSuspended='suspended';caseCanceledByUser='canceled';publicfunctionlabel():string{returnmatch($this){UserStatus::Pending=>'Pending',UserStatus::Active=>'Active',UserStatus::Suspended=>'Suspended',UserStatus::CanceledByUser=>'Canceled by user',};}}

どちらのアプローチが適切であるかは、何をするかの目的によって異なるものであり、開発者の裁量に委ねられます。

State machine

列挙型は、有限ステートマシンを簡単に表現できます。

enumOvenStatus{caseOff{publicfunctionturnOn(){returnOvenStatus::On;}}caseOn{publicfunctionturnOff(){returnOvenStatus::Off;}publicfunctionidle(){returnOvenStatus::Idle;}}caseIdle{publicfunctionon(){returnOvenStatus::On;}}}

この例では、オーブンはオン、オフ、アイドルの3状態を持っています。
しかしオフからアイドル、アイドルからオフに移行することはできず、オフにするには必ずオンの状態を経由しなければなりません。
すなわち、オフから直接アイドルに移行するテストやコードを書いたりする必要がないということです。

もちろん、実際のケースではもっと追加の実装が必要になることも多いでしょうが。

New interfaces

これまで出てきたように、このRFCでは3つの内部インターフェイスが追加されます。
このインターフェイスは、ユーザの作成したコードが列挙型であるか、列挙型である場合はどのような種類であるかを判断するために利用可能です。
ユーザが直接implementsすることはできません。

interfaceEnum{}interfaceUnitEnumextendsEnum{publicfunctioncases():array;}interfaceScalarEnumextendsEnum{publicfunctionvalue():int|string;publicstaticfunctionfrom(int|string$scalar):static;}

Backward Incompatible Changes

enumがキーワードになります。

グローバルスコープにインターフェイスEnumUnitEnumScalarEnumが追加されます。

Open questions

特定のcaseに対してタイプヒントは可能?たとえば

publicfunctionstuff(Suit::Heart|Suit:Diamond$card){...}

Future Scope

代数的データ型のRFCを参照ください。

Grouped syntax

単純なユニット列挙型であれば、まとめて定義を可能にする。

enumSuit{caseHearts,Diamonds,Clubs,Spades;}

メソッドの定義されていない単純なユニット列挙型にのみ可能な文法です。
この列挙型がどのくらい使われるのか不明であり、構文も議論の余地があり、必要に応じて後から追加も可能な構文なので、現時点では対応していません。

Enums as array keys

列挙型のcaseはオブジェクトであるため、連想配列のキーとしては使用できません。
将来的には対応するかもしれません。

Serialization

Suit::Clubs === unserialize(serialize(Suit::Clubs))を安全にシリアライズする方法があれば、後から追加される可能性があります。
今のところは非対応です。

感想

最終的に代数的データ型の実装を目指す遠大な計画の一端です。

個人的にはconstでどうにもならない場面に遭遇したことがないので、PHPにおいて列挙型がどこまで有用なのかよくわかりません。
しかし、PHPで列挙型を作ろうという試みが昔から山ほど行われていることを鑑みると、けっこうな需要はありそうです。
特に型以上の引数値限定はこれまで基本的にはできませんでしたから、この点についてはかなり便利そうです。

このような追加機能については、往々にしてユーザによる勝手拡張の方が便利だったりすることが多いですが、列挙型の場合はextends enumを文法で禁止することで値を完全に保証したり、値にメソッドを生やすことができたりと、公式実装の方が便利っぽいですね。
しかし、いちいちcaseを入れないといけないのは面倒ですね。
他言語ではenum Suit{Hearts, Diamonds, Clubs, Spades}みたいに書けるものも多いのですが、PHPでは構文解析の都合上難しかったのかな?

ところでSplEnumってどうなったんだろう。
RFCでもMLでもプルリクでも誰一人話題に上げていない。

MySQLでうっかり違う行を削除してしまったときに復旧する方法

$
0
0

DELETE FROM テーブル WHERE id=xxのxxを間違ってしまった、みたいなときに軽くバイナリログから復旧する方法です。
そもそもWHERE句を入れてなくて100万件消えたとか、ディスクを読み取り専用にしてextundeleteして、みたいなガチな内容ではありません。

バイナリログってなに?

INSERT/UPDATE/DELETEなどの変更SQLを保存するログファイルです。

MySQLのデータフォルダにデータベース名-bin.000001みたいなファイルがあればバイナリログです。
レプリケーションにも使うので、レプリケーション環境であれば存在するはずです。

バイナリログがなかったら、以下の手段は使えないのでがんばってどうにかしてください。

バイナリログをテキストにする

バイナリログは名前のとおりバイナリなので、そのまま見ようとしても全く読めません。
まずはテキスト形式に変換する必要があります。
環境によっては000001とか000002のように複数のバイナリログファイルがありますが、その場合は更新日時を見てどのあたりが必要なログか確認しましょう。

mysqlbinlog -v /path/to/mysql/database-bin.000001 > /tmp/log.txt

実際はなんだかよくわからないデータも残っていたりするのですが、これで一応人間が読めるテキストファイルになりました。

DELETE文を抽出

cat-n /tmp/log.txt | grep"DELETE FROM `DB名`.`テーブル名`"

これでDELETE文が入っている行が抽出されます。
たくさん見つかった場合は、その中からどこが該当のDELETE文なのかを探す仕事が始まります。

head-n行数+30 /tmp/log.txt | tail-40

こんなかんじでDELETE文の前後の行を取り出せます。
そしてポイントですが、バイナリログではDELETE文にも全てのカラムの内容が入っています。
すなわち、うっかりDELETEしてしまった中身を取り出すことができます。

あとは取り出せた値をINSERTしなおせば復旧完了です。
めでたし。

未確認

TEXT型は取り出せることを確認していますが、BLOBのようなバイナリ型はこれで取り出せるかはわかりません。

ON DELETE CASCADEなどで巻き込まれて削除された場合にバイナリログがどうなるかは確認していません。

今回は調べる必要がなかったからね。

始まる前に終わったJolojo、華麗に復活なるか?

$
0
0

実用HeadlessCMSになりそうな『Jolojo』の紹介と、『SveltElm』な開発スタイル。でも期待をもって紹介されているJolojo

Go言語で書かれており、フロントのSvelteと組み合わせることで、最強最速のプラットフォームが完成します。

The World's fastest CMS system

>>> 世界で最も高速なコンテンツマネジメントシステム <<<

01.png

と、なかなかに挑戦的な文言が目に入ります。

実際にGoogleのベンチマークで計測した結果ではmobile 97 / desktop 99と、他のWebサイトをぶっちぎった好スコアを叩き出しています。

が、その華々しい大言壮語とは裏腹に、実際はどうかというとベーパーウェア一直線でした。

ソースコードは非公開で、本当にJolojoが早いのか、それとも単に静的HTMLを返しているだけなのかもしれません。
開発の進捗状況も第三者にはわかりません。
Updatesは概ね月1で進捗報告がなされていましたが、こちらは2020年1月あたりで更新停止。
公式Twitterは2020/03/10で沈黙。

そもそも公式サイトに複数のJavaScriptエラーが発生している有様からして、その完成度に疑問符が付くことは避けられません。
02.png

そんなわけでこのまま、よくあるマイナーライブラリのようにネットの海の藻屑と消えゆくかと思われました。

突然の復活

とまあそんなような記事を書こうと思っていたのですが、2020/12/17、なんか9ヶ月ぶりに突然復活ツイートをしました。

もうすぐJolojoの開発者プレビューを出すよ!

まさかの復活です。
しかし黙ってた理由はコロナのせいらしいのですが、あんまり関係なくね?

さて、果たしてJolojoの明日はどっちだ!?

ロードマップ

Q3 2020

Svelteフロントエンドが1.0になるよ。
これで最終版かな。

Svelte refactoring completes

Svelteのリファクタリングを完了させるよ。
前も同じことを言ったけど。

Template engine improvements

テンプレートエンジンは、DivとSCSSエディタを導入した高機能なものになるよ。

UI & UX

管理画面がバージョン2になるよ。

Web builder

関係者に向けてWebビルダーをファーストリリースするよ。

Q4 2020

ついにコード公開!
そのままオープンソースるかも?

初めてのフルサイズEコマースサイトを運用はじめるよ。
なぜって、この四半期は、既存のCMSの壁をぶち壊すのに最高の時期なんだ。

SEO | Internal Audits

Webサイト監査をはじめるよ。

eCommerce

電子商取引をフルサポートするよ。

Load site from IBU

外部だけでなく、内部バックアップからもサイトをロードできるよ。
これによって、1ドメインで複数のサイトを提供できるようになるよ。

感想

まあ、なんにしろ実際に出てからでないと評価のしようがありませんね。
管理画面バージョン2とか言われても、バージョン1がどんなものなのかもわからないからさっぱりですし。

しかし何年も進捗が微妙だったことを考えると、今さら本当に前線で戦えるのか少々疑問ではあります。
予想通りやっぱりこんなものだったかってなるのか、それとも、いやはやこれは物凄いものが出てきたってなるのか、ちょっとだけ楽しみに期待して待っていましょう。

【VSCode】保存時に一時的に自動整形しない

$
0
0

コマンド

Ctrl + kCtrl + Shift + s

メモ

保存時に自動整形するようにすることについての記事は腐るほど見つかるのに、自動整形しないで保存したいという記事はなかなか見つからなかいので自分用の備忘録です。

【デレステ】デレステのガシャが確率操作している証拠を発見できなかった

$
0
0

みなさんデレステやってますか?
私は2016/07/30以降、毎日の納税を全て記録しています。
私が金を支払っている唯二つのスマホアプリのうちのひとつです(もうひとつはCOMIC FUZ)。

01.png

そしてソシャゲと言えば確率操作です。
デレステのガシャは果たして信頼できるものなのでしょうか?(タイトルでネタバレ)

なお私は数学素人なので、どこか間違っているかもしれません。
その場合は誰かがコメントで優しく教えてくれるはず。

2019-2020年の出現確率調査

今回は2019年と2020年の2年分の納税について調査してみようと思います。

デレステのガシャはSSR3%、SR10%、R87%の出現率になっています。
欲しいのはSSRですから、それ以外は気にせず、成功率3%の二項分布と考えることにします。

ということでまずは納税結果を集計します。
数え方は単にExcelで=COUNTIF(C:C,"SSR")ってやっただけです。

2019年

レア度枚数割合
R742枚84.32%
SR107枚12.16%
SSR31枚3.52%
合計880枚-

2020年

レア度枚数割合
R1002枚83.78%
SR160枚13.38%
SSR34枚2.84%
合計1196枚-

2020年の枚数が激増しているのは、2019/09/27にメモリアルガシャが導入されたためです。
2年で引いた納税は2076枚となりました。
ちなみに納税額は1枚約60円なので………………おっとこれ以上考えてはいけない。

さて、2019年、2020年共に3%からはわりとずれていますね。
試行回数が少なければたまたまと言うこともあり得ます。
しかし、試行回数を増やせば限りなく3%に近付いていくはずです
今回は1000枚も引いているのにだいぶずれていますが、この程度では収束に足りないのでしょうか?
それとも裏で何か操作が行われているのでしょうか。

調査方法はP値を使います。
調べると帰無仮説とか検定統計量とかよく変な単語が出てきてよくわからなくなりますが、ざっくり言うと、仮定が起こりそうな割合のことです。
SSRの出現率が3%だと仮定してP値を計算し、その結果が0.01より小さければ最初の仮定が誤りである、すなわちSSRの出現率は3%ではない、という背理法のような考え方です。
P値は意味ねーぞみたいな話もいろいろあるみたいですが、よくわからないので気にしないことにします。

さて、起こりそうな割合ってどういうことでしょうか。
私はデレフェス(SSR出現率が6%)中に10連でSSRを3枚引いた(確率は1.68%)ことがあるのですが、このP値を求めると0.018です。
相当低い値ですが、あり得ないこともないということです。

02.png

それでは20連引いてSSRが6枚出現するという事態は起こるでしょうか。
割合としては10連でSSRを3枚と同じなので、実際に起こっても不思議ではなさそうな気がしますよね。
しかしP値を求めてみると0.00087、これは明らかに不自然だという結果になります。
このように、割合としては同じでも試行回数によって異なるP値になるのが特徴です。

でも実際試してみると、試行回数が少ないときのP値って当てにならないかんじがします。
たとえば10連でSSR4枚(確率は0.19%)とか5枚(確率は0.014%)って実在するのですが、SSR4枚のP値は0.0020、そして5枚のP値は0.00015です。
もっと極端な例として、ガシャを2枚だけ引いて2枚ともSSRになるときのP値は0.0036です。
これらの結果によるとSSR出現率が6%であるという帰無仮説は棄却され、理論的にはSSR出現確率は6%ではないということになります。

でも10連くらいだったら、回す人も多いのでたまたま起こっても不思議ではないですよね。
たぶん計測を始めてから結果が出るまでと結果が出てから計測を始めたときの違いとかそんなやつだと思いますが、試行回数が少ないときのP値に関する信頼性に関する話とかってどこかにあるのでしょうか?

おっとだいぶ話が逸れましたが、今回計算するのは試行回数が1000回近いものです。
これくらいあればP値の信頼性も相当高いと考えて問題ないでしょう、きっと。

importscipy.statsasstatsprint("2019年:%s"%stats.binom_test(31,880,0.03))print("2020年:%s"%stats.binom_test(34,1196,0.03))

03.png

2019年のP値は0.37、2020年のP値は0.87となりました。
いずれも0.01よりはずっと上であり、全くもって不自然ではない出現枚数ということです。

ということで、デレステのSSR出現率は操作されていない、あるいは少なくとも露見するような操作は行われていないだろう、という結果になりました。

限定SSRの出現確率はどうなのよ

ところでデレステのSSRはざっくり分けて3種類が存在します。
それぞれ恒常・限定・フェス限と呼ばれています。

恒常SSRは最も一般的なSSRで、一度提供されてしまえば、その後のガシャでは常に出現する可能性があります。

限定SSRは、新しく追加されたあと一週間ほどの期間しか出現しません。
その期間が過ぎてしまえば、基本的にその後入手することはできません。
一年から数年後に復刻という形で再登場することがありますが、後から手に入れたくなっても、そのときをじっと待つしかありません。

フェス限も限定ではあるのですが、こちらは数ヶ月に一度行われる、SSR出現確率が普段の倍の6%になるシンデレラフェスというイベント中に出現します。
従って、限定という名ではありますが比較的入手しやすくなっています。

上記より、恒常とフェス限については操作する意味があまりないと考えられます。
つまり、もしかしたら限定SSRだけ特に出現が絞られているのではないかという疑惑が考えられるわけです。
特定のキャラだけ出現率を絞ってガシャを回させるなんてのはよく聞く話ですからね。

これについての検証は難しい、というか私では立証不可能です。
私は重課金者ではなく、また基本的にシンデレラフェスのときしかガシャを回さないので、限定ガシャの試行回数がないんですよね。

今年はたまたま2020年6月にあった愛を誓うピュア・ブライダルガシャという限定ガシャを回していたので、そちらの結果を使って確認してみましょう。
試行回数は300回なので、信頼性という点ではあまり高くないと思います。

このガシャでは、ここで新登場した限定キャラ3人については出現確率が高めにピックアップされていて、それぞれ0.4%となっています。
そして残りのSSR202種類が合計で1.8%という熾烈な確率です。
300枚引いたら平均としてピックアップがそれぞれ1.2枚ずつ、ピックアップ以外のSSRが5.4枚の合計9枚が引けるということになります。
もちろん確率はそんなに単純にはいかないのと、そもそも試行回数が少なすぎるので、300枚でピックアップ0枚なんてことも普通に起こり得ます。

ということで300枚引いた結果がこちら。

レア度枚数割合
R229枚76.33%
SR62枚20.67%
SSR9枚3%
合計300枚-

取得したSSRは以下のとおり。

恒常[ネクスト☆ページ]荒木比奈
恒常[ネクスト☆ページ]荒木比奈
限定[祝福の花をあなたに]イヴ・サンタクロース
恒常[トゥインクル☆ラブリー]横山千佳
恒常[想いは深く、歌声は遠く]瀬名詩織
限定[祝福の花をあなたに]イヴ・サンタクロース
限定[千年の誓約]黒埼ちとせ
限定[エターナル・マイラブ]川島瑞樹
限定[千年の誓約]黒埼ちとせ
importscipy.statsasstatsprint("愛を誓うピュア・ブライダルガシャ:%s"%stats.binom_test(9,300,0.03))

04.png

P値は1.0、すなわち最大値です。
300連でSSR9枚って、完全に期待値の中央ですからね。

なお、9枚のうちピックアップが5枚です。
ピックアップを5枚取得するP値は0.42であり、こちらも余裕であり得る範囲内です。
というかピックアップを3種類とも総取りしてしまったので、出現率を絞ってるどころかむしろ上揺れしていますね。

以上より、限定SSRの出現確率の操作はしていない、あるいは少なくとも愛を誓うピュア・ブライダルガシャにおいては出現確率の操作をしていないだろう、という結果になりました。
限定SSRの中でも特に[エターナル・マイラブ]川島瑞樹だけ確率が小さく設定されている、みたいな可能性も考えられますが、そこまでくると試行回数が足りなすぎて意味のある数値は出せないでしょう。

ちなみに300連でピックアップ3種類総取りできる確率は34%、ピックアップが1枚も出てこない確率は2.6%、そもそもSSR自体が1枚も出ない確率は0.01%です。
ピックアップをそれぞれ1枚以上取得するP値とかはどう計算すればいいんだろう?

結論

納税、および限定ガシャ愛を誓うピュア・ブライダルガシャについては、共に確率操作はされていない、あるいは少なくとも悟られるような確率操作はされていない、という結果になりました。
これだけをもって『全てのガシャにおいて不正は存在しない』と言い切ることはできませんが、可能性としては『ほとんどありそうにない』と考えてよいのではないでしょうか。

おまけ

と、ここまで事前に書いていたのですが、2021/01/04(つまり今日だ)300連ガシャを回したところ、たいへんな下揺れが起こりました。

レア度枚数割合
R228枚76.0%
SR62枚20.7%
SSR10枚3.3%
合計300枚-

SSR率3%の通常時であれば普通の光景ですが、しかしこれ、実際はSSR出現率が倍の6%になるデレフェス期間だったのです。
P値はなんと0.051で、許容範囲の最下限に近い値です。
これはひどい。
ていうかこれSSR率3%だろ。
きっとそうにちがいない。
動かぬ証拠を掴んでやったぞ!1


  1. 動かぬ証拠になってない。 


Qiitaのいろいろランキング2020

$
0
0

はじめに

これまで毎年いろいろランキングを作ってくれていた @t_nakayama0714氏がお休みになられてしまったのと、といってQiita公式がなんかやってくれたりは特になかったので、無断で勝手に代理作成したものです。
氏はシェル芸を駆使していましたが、私はぺちぱーなので普通にPHPで集計しています。

過去のランキングはこちら。

なお、集計したデータは2021年1月9日あたりのものです。

やること

2019年のやつのほぼパクりです。

  • ユーザ別Contributionランキング
  • ユーザ別記事数ランキング
  • ユーザ別フォロワーランキング
  • 記事別LGTMランキング
  • Organizationsランキング
  • その他分析いろいろ

前準備

とりあえずデータの前準備をしようと思ったのですが、ユーザ一覧ページがなくなったうえにユーザ一覧取得APIはページあたり100人 * 100ページまでしか許されない(つまり最新1万人しか遡れない)ので、ユーザ一覧が作れなくていきなり詰みました。

試しにユーザ一覧取得APIを叩いてみたところ、最新のユーザIDは既に100万を超えていました。
さてどうしようかとAPI一覧を眺めていたら、ユーザIDからユーザ情報を取得するAPIというのがありました。
すなわち、これを1から順に100万回叩けば全ユーザ情報が取れるはずです。

https://qiita.com/api/v2/docs#%E5%88%A9%E7%94%A8%E5%88%B6%E9%99%90

利用制限
認証している状態ではユーザごとに1時間に1000回まで、認証していない状態ではIPアドレスごとに1時間に60回までリクエストを受け付けます。

はい。
全ユーザのリストを取得するだけで一ヶ月以上かかることが判明したので、この手段は使えないようです。

記事ランキングを定期更新しているような人たちであればユーザ情報なども持っていると思いますが、私はそんなもの持ってないので、完全なユーザ一覧の作成は華麗に諦めることにします。

ということで厳密なものではなく、だいたい合ってるだろうランキングを作る方針にします。
具体的には、2019年のContributionランキングと、2020年の殿堂入りに入っているユーザについて集計を行います。
2019年のContributionランキングに入っておらず、2020年の記事が殿堂にひとつも入っていないユーザは、ランキングに影響を及ぼすことはないだろうという推測です。

また、この集計方法の変更に伴い、全ユーザや全記事の集計・統計などはできなくなりました。

そんなわけで方針が決まったので、あとはひたすらユーザページ・記事ページをクロール & スクレイピングしていくだけです
しめやかにsleep()を入れ忘れて爆発四散。

ユーザ分析

ユーザの各種ランキングです。
上記のとおり、残念ながら全ユーザ数やContribution分布などは作れません。

ユーザContributionランキング

ユーザごとのContribution数ランキングです。

ランク前年比ユーザ名総Contribution前年比記事数平均LGTM
10@jnchito63936+10094279229.16
2+1@rana_kualu53573+14344434123.44
3-1@hirokidaichi53166+4151451181.47
40@suin50141+10959117642.64
50@icoxfog41738828+1857155250.5
6+7@Yametaro35577+1864069515.61
7+1@drken35489+1314451695.86
8@mpyw2879231292.28
9-3@opengl-808027205+287128097.16
10-3@mizchi24938+124526893.05
11+12@baby-degu22372+821976294.37
12-1@youwht21283+236744483.7
13-4@KeithYokoma21266+572143148.71
14+10@uhyo20908+702775278.77
15-5@yuku_t19681+3220596
16+12@TakahikoKawasaki18673+586547397.3
17-5@awakia18673+405156119.7
18-3@shibukawa18545+2256140132.46
190@poly_soft17265+175244392.39
20-3@koher17177+145576226.01
21-7@b4b4r0717106+65857300.11
22-6@edo_m1816785+76541340.64
23-5@zaru16688+970157106.29
24-3@kenmatsu415943+119472221.43
25-5@cognitom15511+11698158.28
26@ryuichi120814750119123.95
27-2@tag121614589+1186122119.58
28+8@teradonburi14487+2619131110.59
29-7@haminiku14416-676189.68
30-4@takeharu14332+97918796.22
31+22@soarflat14321+424028511.46
32+9@alt14009+28450-
33-6@tonkotsuboy_com13870+1004114121.67
34-3@t_nakayama071413803+141642328.64
35+12@zembutsu13315+263814095.11
36-4@tadsan13158+81820564.19
37+6@Qiita13152+201952630.4
38+24@gold-kou13116+369148273.25
39-4@Hironsan12831+95251251.59
40@ucan-lab1263117472.59
41+22@zaburo12573+320044128.51
42-9@yimajo12501+25018268.69
43-13@susieyy12392-1551242.98
44-7@ynakayama12344+48920161.41
45-16@kazunori27912299-17944279.52
46-8@hshimo12149+32931039.19
47+11@shizuma11964+2284109109.76
48-8@uasi11906+33712595.25
49-15@appwatcher11899-22560198.32
50-11@kawasima11898+17983143.35
51-9@hkusu11542+40823349.54
520@jabba11469+109735327.69
53-5@howdy3911449+80874154.72
54-10@kidach111418+33985134.33
55-10@tukiyo311338+54817916.33
56+10@kaityo25611205+220330037.35
57-7@kazukichi11191+58052215.21
58-4@tbpgr11153+121875614.75
59-13@Quramy11063+341102108.46
60+7@Ted-HM10968+223516685.5
61-12@joker100710591-2410699.92
62-1@n0bisuke10391+93445123.04
63-7@y_hokkey10199+42772141.65
64-4@tmknom10188+62612849
65-10@amay07710170+37435228.89
66-9@kawaz10143+39415963.79
67@omiita1008125403.24
68@ulwlu1004612837.17
69+5@shuntaro_tamura9978+182466151.18
70+22@naoki_mochizuki9685+248118538.06
71-12@vvakame9620+5262155.16
72@ryo2132955614366.83
73-3@mima_ita9416+101416457.41
74-3@tenntenn9387+105180117.34
75-6@takahirom9386+93214664.29
76-4@pugiemonn9373+115828532.89
77+12@koshian29242+195212474.53
78-27@usagimaru9242-124417552.81
79@rubytomato@github918321642.51
80-15@okappy9125+11929314.66
81-17@sion_cojp9107+1842216.83
82+2@toshihirock9073+148027832.64
83-4@nonbiri158884+98934325.9
84+12@toRisouP8872+213310187.84
85@tomo_makes882932275.91
86@kahirokunn873611178.7
87-14@jacksuzuki8710+50610871
88-20@syui8655+14227631.36
89-7@mochizukikotaro8457+64731426.93
90+5@MahoTakara8430+166130727.46
91+6@kaizen_nagoya8284+158624873.33
92-7@potato4d8260+75959140
93-10@disc998128+43029280.28
94-14@terrierscript8125+27013958.45
95-18@KanNishida8095+15279102.47
96@yuno_miyako807626310.62
97-21@tatesuke8044+9041196.2
98-23@yuya_presto8024-440200.6
99-1@ritukiii7961+131611768.04
100-10@nekoneko-wanwan7927+63857139.07

一位は2017年から安定して独走している @jnchitoさんです。
おめでとうございます。
今後彼の寝首を掻く人は現れるのでしょうか。

Contribution数の増加が最も多かったのは @Yametaroさんで、+18640となっています。
もし昨年始めいてたとしても、いきなり18位に入るくらいの勢いですね。

昨年ランク内にいたうち、今年の上昇幅が最も大きかったのは62位から38位へ+24上昇した @gold-kouさんでした。
おめでとうございます。

新たなランクインは10名です。
新人賞は @mpywさんで、3万近いLGTMを稼いでいきなり8位に登場です。
おめでとうございます!
……あれ?
この人だいぶ前からいなかったっけ?

と調べてみたら、2018年のランキングにはいたのに2019年のランキングで抜け落ちていたみたいです。
いったいどうしてこうなった。

というわけで本当の新人賞は @ryuichi1208さん……君も2018年おったやんけ。
というわけで三度目の正直、本当の新人賞は @ucan-labさんでした。
おめでとうございます。
2018年に活動開始し、主にVSCodeLaravelの記事を書かれているようです。

ちなみに昨年の上位100名のうち、今年退会した人はいないようでした。
例の問題は意外と深刻な影響はなかったようです。
もちろん影響が完全にゼロというわけではなく、29位 @haminikuさん、43位 @susieyyさんなどは累計LGTM数が減少するという珍しい結果になっています。
というか78位 @usagimaruさんの-1244ってなに?
さすがにこれは記事を削除したとかの別の原因だと思われます。

ユーザ記事数ランキング

記事数のランキングです。

ランク前年比ユーザ名記事数前年比Contribution数
10@7of96163+845529
20@kaizen_nagoya2487+2638284
30@YumaInaura2189+2536685
4+1@ohisama@github1940+541717
5-1@tukiyo31791+11711338
60@suin1176+10550141
7+1@ekzemplaro1012+3761703
8-1@tbpgr756+411153
9@miriwo6352163
10+4@Q11Q465+71574
11-2@chen7897499457080
12+3@n0bisuke451+6010391
13-3@zaburo441+2912573
14@rana_kualu43453573
15-2@Nabetani426+271893
16-4@jkr_2255417+146682
17+2@cielavenir413+35915
18-7@edo_m18413+816785
19-3@snaka405+173993
20-3@tcsh389+21483

新人賞にして最多投稿賞は @miriwoさんです。
2020年7月には1年間毎日投稿するという偉業を成し遂げ、さらにその後もほぼ毎日投稿を続けているようです。
あとなんか私がランクインしていますが、私は毎週月曜日にしか投稿していないので、そんなに多かったか?って感じます。

ユーザフォロワー数ランキング

どれだけウォッチされているかのランキングです。

ランク前年比ユーザ名フォロワー数前年比Contribution数
1+3@Yametaro5435+247135577
2-1@jnchito4847+81763936
3-1@kaizen_nagoya4361+4588284
4-1@hirokidaichi4267+39953166
50@poly_soft3853+102517265
6+3@drken3276+124235489
7+1@suin2633+57750141
8-2@mizchi2609+12024938
9-2@icoxfog4172580+15438828
10@mpyw248528792
110@rana_kualu2436+51253573
12+1@kenmatsu42024+15415943
13-3@dankogai1915-163300
14-2@taguchi1858-2727
15-1@yukihiro_matz1839-18119
160@mattn1717+636545
17-2@supermomonga1704-50839
18-1@youwht1650+18721283
19-1@kazukichi1464+7311191
20-1@Qiita1350+8213152

@Yametaroさんが2千人以上のウォッチャーを稼いで一気にトップに躍り出ました。
こちらでも新登場している @mpywさんは例によって集計漏れだと思われます。

記事も Contributionも全くないのにランクインしている @taguchiさんって何なのって思っていたのですが、ドットインストールの中の人だからみたいですね。

記事分析

残念ながら総記事数の変遷などの集計はできませんでした。

記事LGTM数ランキング

Qiita全体の記事のLGTM数ランキングです。

ランク前年比LGTM前年比記事
1010642+1869Markdown記法 チートシート
208622+446ロシアの天才ハッカーによる【新人エンジニアサバイバルガイド】
3+18545+1901プログラミングでよく使う英単語のまとめ【随時更新】
4-18049+816ペアプログラミングして気がついた新人プログラマの成長を阻害する悪習
5+16697+647うまくメソッド名を付けるための参考情報
6-16538+132非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選
7+96079+2038一番分かりやすい OAuth の説明
8-16021+386【まとめ】これ知らないプログラマって損してんなって思う汎用的なツール 100超
9+15391+561イマドキのJavaScriptの書き方2018
10+245349+1887AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~
11-25245+386新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡
12-45171+60数学を避けてきた社会人プログラマが機械学習の勉強を始める際の最短経路
13+75131+1251VSCodeのオススメ拡張機能 24 選 (とTipsをいくつか)
1404833+604オブジェクト指向と10年戦ってわかったこと
15-44808+45もう保守されない画面遷移図は嫌なので、UI Flow図を簡単にマークダウンぽく書くエディタ作った
16+74637+773開設後3週間で収益10万円を得た個人開発サイトでやったことの全部を公開する
17+14563+610Chrome拡張の高速な英語辞書ツールをつくりました(Mouse Dictionary)
18+34553+682エンジニアの情報収集法まとめ
19+34553+6842018年の最先端バックエンドエンジニアに必要なスキルについて考えてみました。
20+64454+746質問は恥ではないし役に立つ
21-94365+3インフラエンジニアとしてよく使うコマンド集
22-94311+64初心者向け、「上手い」シェルスクリプトの書き方メモ
23+14295+496Gitのコミットメッセージの書き方
24-74273+258Reactを使うとなぜjQueryが要らなくなるのか
25-104183+91何かのときにすっと出したい、プログラミングに関する法則・原則一覧
264095Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したい
27+114092+857【図解】Dockerの全体像を理解する -前編-
28+213986+1077いまさらだけどDockerに入門したので分かりやすくまとめてみた
29-43978+196Pythonを書き始める前に見るべきTips
30-113972+87エンジニアなら知っておきたい、絵で見てわかるセキュア通信の基本
31-23926+258インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識
323916要件定義~システム設計ができる人材になれる記事
333905良いコードの書き方
34-23845+324GitHubで使われている実用英語コメント集
35-43841+304「AWS is 何」を3行でまとめてみるよ
36+73823+706使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
37-73794+237Vim幼稚園からVim小学校へ
38-103788+106ウェブカツ運営者が語る!エンジニアで稼ぐために大切な20のコト
39-33787+387AWSアカウントを取得したら速攻でやっておくべき初期設定まとめ
40+23755+634個人でも使える!おすすめAPI一覧
41-23755+573Go言語の初心者が見ると幸せになれる場所 #golang
423717エンジニアの劣等感との付き合い方
43-163659-47ネイティブと働いて分かった英語コミットメッセージの頻出動詞10つ
443612プロジェクトリーダーというお仕事
4503592+513すべての新米フロントエンドエンジニアに読んでほしい50の資料
46-23469+358[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか
47-123466+54コードを書く際の指針として見返すサイトまとめ
483379メンバーに恨まれそうな3つのコードレビュー施策を徹底したら、逆にメンバーが爆速で成長した話
49+233378+8942020年のフロントエンドマスターになりたければこの9プロジェクトを作れ
50-93369+236モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう
51+103307+586不思議の国のSE用語
52-153259-24特にプログラマーでもデータサイエンティストでもないけど、Tensorflowを1ヶ月触ったので超分かりやすく解説
53-13219+358プログラミング勉強を加速させる7つの習慣
54+313213+860Markdown記法 サンプル集
553205ls よりも exa を使おう!モダンな Linux コマンド達を紹介
56-103186+110VagrantとDockerについて名前しか知らなかったので試した
57-103154+173画像処理の数式を見て石になった時のための、金の針
58-183151-192016年 独りで新規WEBサービスを開発・運用した際の知見
59+203142+727(下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
60-123140+168JavaScriptを読んでて「なにこれ!?」と思うけれど調べられない記法8選。
61-113097+221トップデベロッパーになるために作成したいアプリ8選
62+163074+654いまさらだけどGitを基本から分かりやすくまとめてみた
63-42945+205個人的に超絶為になったので新人エンジニアに勧めたい記事まとめ
64-132940+69脱初心者を目指すなら知っておきたい便利なVimコマンド25選 (Vimmerレベル診断付き)
65-102939+153新人プログラマに正月休み中を使って読んでみてほしい技術書をセレクトしてみた。
66+42938+441初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」
67-142931+122不安とストレスから解放される見積りとスケジュール方法
68-32920+247WebAPIでエラーをどう表現すべき?15のサービスを調査してみた
69-132896+129ゼロからDeepまで学ぶ強化学習
70-72846+141新人プログラマに知ってもらいたいメソッドを読みやすく維持するいくつかの原則
71-142825+652017年のフロントエンドエンジニアならこの程度は知ってて当然だよな?
72-182806+15プログラマが独立・起業する時によくするミスと対策 まとめ
73-152786+38Linux開発環境の基礎知識
7427851時間で出来るWordPress環境構築(※永久無料・・・だった)【※2020/7/1より約300円/月が有料になります】
752753Kaggleに登録したら次にやること ~ これだけやれば十分闘える!Titanicの先へ行く入門 10 Kernel ~
762751【全部無料】ハマると時間が秒で過ぎる英語圏のプログラミング系サイトまとめ【英語学習】
77-82733+224なぜ仮想DOMという概念が俺達の魂を震えさせるのか
78-162727+17究極のIT系最新技術情報収集用Slackチーム公開 - モヒカンSlack -
79-152726+37新卒からの質問をソシャゲっぽい仕組みにしたら捗った話
80-142698+88プログラミングで一番難しいのは「見積もり」だと思う
81-212689-37英語コミットコメントに使えるオシャレフレーズ集
82-152646+63コーディングをするときに鼻血がでるほど便利なwebツールリスト
83-152634+6130分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで
84-132610+120クラスの命名のアンチパターン
852573新規Webサービスを独りで開発・運用する際に立ちはだかった壁とそれを乗り越えた方法まとめ【個人開発】
862565数時間で完全理解!わりとゴツいKubernetesハンズオン!!
872531エンジニアなら知っておきたい生産性を爆上げするツール8選
88+72497+279iPhone/iPad/Apple Watch解像度(画面サイズ)早見表
89-22490+177プログラマーの君! 騙されるな! シェルスクリプトはそう書いちゃ駄目だ!! という話
902481スナック「jQuery」
91-172480+29Electronでアプリケーションを作ってみよう
92+42477+259【今日からできる】コミットメッセージに 「プレフィックス」 をつけるだけで、開発効率が上がった話
93-102465+81さよなら本番サーバー
94-122440+44[ver 1.2] Git でよく使われるコマンドにイラストによる説明を加えて1枚のチートシートにまとめてみた
952438君には1時間でGitについて知ってもらう(with VSCode)
96-212424-7日本の行政機関等が公開しているAPIについてのまとめ(2016年8月17日暫定版。随時更新)
97-212415-14英語のコメントや issue で頻出する略語の意味 (FYI, AFAIK, ...)
98-212414-9httpsだからというだけで安全?調べたら怖くなってきたSSLの話!?
99-112397+129エンジニアは全員技術記事を書くことを習慣化した方がいいぞ
100-162389+20Android開発を受注したからKotlinをガッツリ使ってみたら最高だった

Markdown記法 チートシートがついに5桁の大台に乗りました。
まあ、Qiitaで何かやろうとしたらとりあえず最初に参照する記事ですからね。
これからもQiitaの人口が増えるたびにLGTM数が増えることでしょう。

新規ランクインは15記事です。

ランクLGTM数記事
264095Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したい
323916要件定義~システム設計ができる人材になれる記事
333905良いコードの書き方
423717エンジニアの劣等感との付き合い方
443612プロジェクトリーダーというお仕事
483379メンバーに恨まれそうな3つのコードレビュー施策を徹底したら、逆にメンバーが爆速で成長した話
553205ls よりも exa を使おう!モダンな Linux コマンド達を紹介
7427851時間で出来るWordPress環境構築(※永久無料・・・だった)【※2020/7/1より約300円/月が有料になります】
752753Kaggleに登録したら次にやること ~ これだけやれば十分闘える!Titanicの先へ行く入門 10 Kernel ~
762751【全部無料】ハマると時間が秒で過ぎる英語圏のプログラミング系サイトまとめ【英語学習】
852573新規Webサービスを独りで開発・運用する際に立ちはだかった壁とそれを乗り越えた方法まとめ【個人開発】
862565数時間で完全理解!わりとゴツいKubernetesハンズオン!!
872531エンジニアなら知っておきたい生産性を爆上げするツール8選
902481スナック「jQuery」
952438君には1時間でGitについて知ってもらう(with VSCode)

Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したいが4000票以上を獲得しました。
エンジニアはコーディング力だけではなく日本語力(英語力でもいいけど)も大事ですからね。

2019年の新着は26記事、2018年は23記事だったので、今年はだいぶ減少しました。
100位でも2400LGTMが必要ですから、今後もハードルが上がっていくのは避けられないでしょう。

そもそも、まずジャンル選びの時点で相当数が脱落してしまいますからね。
専門性が高い記事ほど、どれだけ優れていようともLGTM数はどうしても控えめになります。
そういった隠れた良い記事を掘り出そうという研究もあるにはありますが、なかなか難しいところですね。

Organization分析

最後にOrganization分析です。

Organizationは一覧が残っているので、ここからデータをぶっこ抜いてくることができました。
つまり(ミスがなければ)完全なランキングです。

全体

Organization総数は、べつに集計とかしなくても一覧の最終ページを見ればいいんですよ。

最終65ページ目に14組織だったので、64*20+14=1294です。

昨年は958だったようなので、336組織が増えました。
増加数は昨年とほぼ同じで、順当に成長しているようです。

Organization別LGTMランキング

まずは組織ごとのLGTM数ランキングです。

ランク前年比名前LGTM数前年比記事数メンバー数
1+5@admin-guild112708+526952865182
20@tis103777+34154160491
30@yumemi96609+272512141128
4-3@mercari93783-16222161783
5-1@yyphp87430+23799252923
6-1@sonicgarden73336+1109362518
7@engineerlife70979234970
8-1@dena_coltd65362+123521464116
9@craftsman_software5364414806
10-2@rector53183+4171453
11-1@shouldbee52720+1122214393
12@dmmcom52643119071
13-1@nri43459+890452660
14-5@cyberagent41190-570085760
15-2@future41115+665891495
16-2@zozotech40423+78131568146
17-2@iotlt39328+83333054128
18+6@ntt-data-msi38399+136791015
19-8@wantedly37955+209348629
20-4@crowdworks34108+329138834
21+1@unity-game-dev-guild32702+7011138757
22-5@yahoo-japan-corp32692+232392373
23-3@dwango32519+655779372
24-5@lifull31682+48701193100
25@phper-oop2934354712
26-8@plaid29259+168550036
27@m3dev2830370743
28-3@synapse27709+33923122
29-1@jrits26288+396298345
30@qiitadon26111175244

1位になったのは、LGTM数記事数メンバ数すべてを圧倒的に増やした@admin-guildです。
他にも5位の@yyphp、初登場7位の@engineerlifeなどは企業ではなくコミュニティです。
従って会社・学生にかかわらず自由参加・複数参加することができるのでLGTM数も増やしやすいという有利な点があります。

そんな中でも企業単位で健闘している2位@tis、3位@yumemi、6位@sonicgardenなどは流石ですね。

上位陣で総LGTM数が減少した組織は4位@mercariと14位@cyberagentでした。
特に@mercariは昨年1位から大きくLGTM数を落としています。

初登場9位の@craftsman_software@suinさんの参加、初登場12位の@dmmcom@mpywさんの参加によるものだと思われます。
個人上位層の加入によってわりと大きく変動しますね。

Organization記事数ランキング

組織単位での記事数ランキングです。

ランク前年比名前記事数前年比LGTM数平均LGTM
10@iotlt3054+8933932812.88
2+3@admin-guild2865+140711270839.34
3-1@yyphp2529+3878743034.57
4@engineerlife23497097930.22
5-2@yumemi2141+2039660945.12
6@qiitadon17522611114.90
7-3@mercari1617-2109378358.00
80@tis1604+50810377764.70
90@zozotech1568+4784042325.78
10@craftsman_software14805364436.25

こちらも@admin-guildの増加が圧倒的で、首位@iotltの首元まで迫ってきました。
4位@engineerlife、6位@qiitadonなど、こちらもやはりコミュニティ組織の躍進が大きいですね。

Organizationメンバ数ランキング

単純にメンバ数のランキングです。

ランク前年比名前メンバ数前年比LGTM数1人あたりLGTM
1+6@admin-guild182+94112708619.27
2+1@zozotech146+3540423276.87
3-1@yumemi128+796609754.76
3-2@iotlt128+339328307.25
5-1@dena_coltd116+1765362563.47
60@lifull100+931682316.82
7+1@future95+841115432.79
8+1@tis91+101037771140.41
9-4@mercari83-15937831129.92
100@yahoo-japan-corp73-332692447.84

メンバ数は誰でも参加できるコミュニティが有利なはずですが、その中でもしっかり多くの開発者が情報発信している@zozotech@yumemiは流石です。

しかし@mercariは何か大量リストラでもあったんですかね。

Organization1人あたりLGTM数ランキング

最後は1人あたりのLGTM数ランキングです。

ランク名前一人あたりLGTMLGTM数メンバ数
1@rector17727.67531833
2@shouldbee17573.33527203
3@synapse13854.5277092
4@craftsman_software8940.67536446
5@pugiemonn_com885088501
6@meson8383.5167672
7@ntt-data-msi7679.8383995
8@arow-oss737973791
9@consensus-base6074121482
10@sirok499599902

少人数組織は@rector@hirokidaichiさん一人で、@shouldbee@suinさん一人で稼いでるみたいに個人力に大きく依存してしまうので、偏ったランキングになってしまいます。
極端な話、私が一人組織を作れば断トツトップに躍り出られますからね。
やりませんけど。

ということで20人以上の組織に絞ったランキングが以下です。

ランク名前一人あたりLGTMLGTM数メンバ数
1@yyphp3801.38743023
2@wantedly1308.793795529
3@tis1140.4110377791
4@mercari1129.929378383
5@sakura_internet1107.322436122
6@engineerlife1013.997097970
7@crowdworks1003.183410834
8@plaid812.752925936
9@repro766.172298530
10@iwate-pu762.222058027

一部参加者だけではなく、構成員の多くがきちんと記事を書いているということなので、組織全体でのモチベーションの高さが窺えますね。

おわりに

graphQLめんどいのでRESTも用意してほしい。

Qiita APIがわりと役に立たなかったため、ユーザページや記事を気合いでスクレイピングする羽目になりました。
まあ、Qiita APIは各ユーザが自分の情報に関して使うものであって、全ユーザをどうこうするために作られたものではないから当たり前ですが。

ランキングの上位記事、上位ユーザというのは何れもそれなりに理由があってその位置にいるものなので、関係のない分野だからと見ていなかった記事やユーザについても、試しに覗いてみるのも面白いかもしれません。
新たな知見や興味が産まれるかもしれませんよ。
ちなみに個人的に調査中に目を通した中で一番笑った記事はこれでした。

自分が見たかったから始めたのですが、とても大変だったので来年はたぶんやりません。
最後に、昨年までこんな面倒くさいことを毎年やってくださっていた @t_nakayama0714氏に感謝を。

JavaScript ベスト・オブ・ザ・イヤー 2020

$
0
0

00.png

JavaScriptライブラリのトレンドを紹介しているbestofjs.orgが、2020年に最もホットであったJavaScriptライブラリのランキングを発表しました。
選考基準は現在のスター数ではなく、『2020年の一年間で増えたスターの数』です。
過去流行っていたけど落ち目となった技術は出てこないので、最近注目されている技術がわかります。

ちなみに2016年の総合ランキング1位はVue.js、2017年の総合ランキング1位はVue.js、2018年の総合ランキング1位はVue.js、2019年の総合ランキング1位はVue.jsです。

以下は2020年のランキング、2020 JavaScript Rising Starsの日本語訳です。

JavaScript ライジングスター 2020

5回目のJavaScript ライジングスターにようこそ!

このランキングのコンセプトは、昨年までと同じです。
すなわち、2020年の一年間でGitHubに追加された☆の数を比較することで、どのプロジェクトが最も注目を集めたかを数字で確認します。

以下のチャートは、2020年の一年間にGitHubで増加したスターの数を比較したものです。
Webプラットフォームに関するベストプロジェクトを集めたリストであるBest of JavaScriptからの分析となります。
各プロジェクトをクリックすると、プロジェクトの詳細を閲覧することができます。

総合ランキング

04.png

1位: Deno
2位: Vue.js
3位: React
4位: Playwright
5位: VS Code
6位: esbuild
7位: Vue Element Admin
8位: eDEX-UI
9位: Next.js
10位: Tailwind CSS

2020年は様々な理由で特別な年になりました。
最も目を引くことは、これまで5年間首位を独走してきたVue.jsを抜き去り、Denoが一位になったことです。

DenoはNode.jsの生みの親Ryan Dahlによる新たなJavaScriptランタイムです。
Node.jsのこれまでの10年間の経験と反省を生かし、多くを改善しているため、Node.jsの後継と思われがちです。
主な機能としては、

  • デフォルトでTypeScript対応。ただしJavaScriptでコードを書くこともできる。
  • 一極集中したパッケージマネージャがなく、任意の依存関係を任意のURLから読み込むことができる。
  • Deno標準ライブラリは、Node.jsでは個別にパッケージをインストールしなければならなかったような一般的な用途のライブラリを最初から提供する。
  • Denoは可能なかぎりWeb標準に従っている。(例:Fetch API)
  • インポートはES Modulesを使用。
  • テストランナーやデバッガーを標準装備。

Denoのエコシステムはまだまだ発展途上ですが、Denoの話題性を考えると、今後大きく変化することが期待されます。

Denoの成長は、2つの大きなトレンドを裏付けています。

  • フロントエンドとクライアントサイドでのTypeScriptの台頭
  • Snowpackなどのソリューションによってオンザフライで提供されるES Modulesの成長。

フロントエンド フレームワーク

1位: Vue.js +22.5k
2位: React +19.8k
3位: Angular +13.3k
4位: Svelte +12.0k
5位: Alpine.js +11.5k
6位: vue-next +5.9k
7位: Solid +3.3k
8位: Preact +3.0k
9位: htmx +2.7k
10位: Stimulus +2.0k

いつものようにVue.jsReactが頂上決戦を繰り広げています。

その後ろでは、2019年に3番手をSvelteに奪われたAngularが、ふたたびその位置を奪還しました。

ベスト5の新顔はAlpine.jsで、これはLaravel LiveWireの作者によって作られたミニマルなリアクティブフレームワークです。
Vue.jsとAngularの両方から、カスタムHTMLディレクティブや双方向バインディングといったアイデアを拝借しています。
HTMLに古き良き<script>タグを追加するだけで簡単に使うことができ、ビルドプロセスも不要で、HTMLマークアップだけで全てを動かすことができます。
本格的なフレームワークを導入することが困難な既存のWebページをさくっと強化する目的については、最も適切なソリューションであるかもしれません。

Webページにインタラクティブ性をもたらすだけの非常に軽量なソリューションであるため、Elixir Phoenixのようなフレームワークともうまく連携して同居できます。
Alpine.jsTailwind CSSを最初からまとめておいたPETALのようなプロジェクトも存在します。
こちらについては後ほど語りましょう。

Node.js フレームワーク

1位: Next.js +15.5k
2位: Strapi +11.8k
3位: Nest +10.3k
4位: Nuxt +8.2k
5位: Blitz +6.0k
6位: Redwood +5.5k
7位: Express +4.6k
8位: Fastify +3.8k
9位: umi +2.9k
10位: Koa +2.3k

Node.jsフレームワークには大きく2つの種類が存在します。

ひとつはNext.jsNuxtのようなフルスタックフレームワークで、ReactやVue.jsなどをサーバサイドに持ってくるアプリケーション構築方法については賛否両論があります。

もうひとつは昨年のチャンピオンNestFastifyなどが属する、サーバ側のみで動作する古典的なフレームワークです。

この分野では2018年にトップだったNext.jsが再びチャンピオンに返り咲きました。
当初はReactをSSRするだけのソリューションとして名を上げましたが、今ではReactでフルスタックWebアプリケーションを構築するソリューションの筆頭になっています。
最新バージョンでは動的ページと静的ページの垣根を取り払うIncremental Static Regenerationにも対応し、多くのユースケースで最適な選択肢になりつつあります。

フルスタックといえば、BlitzRedwoodは、それひとつだけで完全なWebアプリケーションを構築できるという最高の開発者体験を提供することを目的としたプロジェクトです。

それにしても浮沈の激しいJavaScriptの世界で、11年前に誕生したExpressがいまだに一定の地位を保っているのは興味深いですね。

React エコシステム

1位: Next.js +15.5k
2位: REact Query +13.6k
3位: Recoil +11.1k
4位: Ant Design +10.9k
5位: React Hook Form +10.8k
6位: Material UI +10.6k
7位: Create React App +10.1k
8位: Chakra UI +10.0k
9位: swr +8.9k
10位: Gatsby +7.4k

2020年のReactエコシステムのテーマは安定性でした。
React17では破壊的変更を行わず、将来に向けての布石を仕込みました。
それがReact Server Componentsです。

React Server Componentsはクライアントのバンドルサイズを縮小し、起動にかかる時間を改善します。
さらにデータの取得、データベースやファイルシステムなどデータソースへのアクセスも簡単になります。

Next.jsは、Reactアプリケーションを構築するための最も有名なソリューションに成長しました。
React Server Componentsの最初のアプリになることでしょう。
React QueryRecoilReact Hook Formといったサポートライブラリは、hooksを主軸に進化、円熟してきました。
それぞれがReact開発の一部を簡素化してくれます。
これらのコンポーネントライブラリを組み合わせることで、React開発者はこれまで以上に多くのツールを手に入れることができるでしょう。

Vue エコシステム

1位: Vue Element Admin +16.0k
2位: Vite +14.1k
3位: Nuxt +8.2k
4位: Element Plus +7.3k
5位: vue-next +5.9k
6位: Vuetify +5.8k
7位: Wiki.js +5.7k
8位: Element +5.5k
9位: Ant Design Vue +4.2k
10位: Vant +4.1k

2020年のVueコミュニティ最大のニュースは、Vue3のリリースです。

Vue2に存在した幾つかの問題を解決するために、Composition APIという仕組みが導入されました。

  • コンポーネント内の論理的な繋がりによってコードを整理することが難しかった。
  • コンポーネントをまたいだコードの再利用が容易になる。 (Vue2のmixin、mixing factory、scoped slots等では不十分だった)
  • TypeScriptサポートが改善された。

バージョン3で導入された変更については、マイグレーションガイドをチェックしてみてください。

2020年には新たなWeb構築ツール、Viteが誕生しました。
ES modulesに対応し、コマンドラインからVueアプリケーションを構築する最速の方法です。

Angular エコシステム

1位: ngx-admin +2.5k
2位: Material Design for Angular +1.5k
3位: Scully +1.4k
4位: Angular CLI +1.3k
5位: NG-ZORRO +1.2k

Angularのランキングは昨年とあまり変わりませんが、3位に新たなプロジェクトが登場しました。
ScullyはAngularにJamstackをもたらす静的サイトジェネレータです。
このプロジェクトは2019年12月に登場し、そしてわかりやすいドキュメントが存在します。

Angularは2020年に3つのメジャーバージョンがリリースされました。

2月にはバージョン9がリリースされました。
主な変更点はIvyコンパイラの導入で、これによってバンドルサイズが減少し、またビルドプロセスに大きな改善がもたらされました。
さらに年の後半にはバージョン10バージョン11がリリースされました。

Angularチームの2020年後半の主な仕事は、コミュニティの声に耳を傾けることでした。
コミュニティのニーズを理解するために、issueやPRに対応することに大きな努力を行いました。
また、チームが取り組んでいることの共有や、今後のロードマップの公開も行いました。

ビルドツール

1位: esbuild +16.6k
2位: Rome +14.2k
3位: Vite +14.1k
4位: Snowpack +10.1k
5位: Webpack +4.5k

2020年はビルドツールの当たり年で、多くの新しいトレンドが産まれました。

SnowpackViteはES modulesの将来に賭けたアプローチです。
開発中のコードはバンドルせず、プロダクションコードのビルド時のみバンドルする方針で、非常に高速なフィードバックループを持っています。

swcesbuildは、それぞれRustとGoで書かれており、TypeScriptをサポートしていて、そして信じられないほどの高速で動作します。

Webpackは設定が複雑すぎると言われることが多く、よりシンプルに書けるParcelRollupが成熟してきました。
とはいえビルドツールの中心はいまだWebpackであることは変わらず、そしてWebpackの新たなキャッシングレイヤはビルドのパフォーマンスを大幅に改善します。

Monorepoがメインストリームになりつつあります。
YarnとLernaが広く使われ、そしてnpm 7も参加してきました。

個人的に2021年の去就を注目しているのはRome、Toast](https://toast.dev/)、[Turborepo](https://turborepo.com/)です。

CSSフレームワーク

1位: Tailwind CSS +15.5k
2位: Bootstrap +8.2k
3位: Bulma +4.2k
4位: new.css +3.1k
5位: Halfmoon +2.0k

昨年はなかった項目ですが、Tailwind CSSの躍進と、そのユーティリティファーストの姿勢を評してこのセクションを追加しました。

BootstrapBulmaといった既存のCSSフレームワークに比べて、開発者がクラス名を合成してページやコンポーネントをスタイル化するための命名規則を提供しています。
State of CSSのアンケートにおいても、最も満足度の高いフレームワークになっています。
先日バージョン2がリリースされ、ダークモードなど多くの新機能が追加されました。

CSS in JavaScript

1位: Styled Components +4.8k
2位: Twin +2.8k
3位: Emotion +2.5k
4位: Linaria +1.8k
5位: Theme UI +1.8k

テスト

1位: Playwright +19.7k
2位: Storybook +12.3k
3位: Puppeteer +10.6k
4位: Cypress +9.0k
5位: Headless Recorder +6.0k

モバイル

1位: React Native +8.8k
2位: Expo +4.3k
3位: Quasar +4.0k
4位: Ionic +2.8k
5位: Sonar +1.8k

JSコンパイラ

1位: TypeScript +10.4k
2位: swc +3.4k
3位: Babel +2.7k
4位: Reason +818
5位: Flow +799

状態管理ライブラリ

1位: Recoil +11.1k
2位: XState +5.1k
3位: Immer +4.2k
4位: Zustand +3.2k
5位: Redux +3.2k

GraphQL

1位: Gatsby +7.4k
2位: Hasura GraphQL Engine +5.9k
3位: Redwood +5.5k
4位: Prisma +4.0k
5位: Apollo client +2.4k

学習リソース

1位: JS Algorithms & Data Structures +31.9k
2位: Node.js Best Practices +20.2k
3位: You Don't Know JS +18.0k
4位: Clean Code +15.1k
5位: 30 seconds of code +13.3k

まとめ

Best of JSが追跡している多くのカテゴリにおいて、幾つかの新しい潮流が発生し、JavaScriptの世界は今年も素晴らしい年になりました。

バックエンド開発者は今すぐDenoを使って、依存を気にすることなくTypeScriptを楽しむことができます。

フロントエンド開発者はesbuildSnowpack、そしてViteなど、より高速でシンプルなビルドソリューションを手に入れることができました。

ツールにおいては、NPM 7がひとつのリポジトリで複数のパッケージを扱えるようになるworkspacesをリリースしました。
これはライバルであるYarnが先に提供していた大きな利点のひとつです。

スタイルについては、よりシンプルなコンセプトを中心としたエコシステムを構築する、Tailwind CSSのような方向性のソリューションが他にも現れています。

2021年には何が期待できるでしょうか?

React Server Componentsがどのようなものになるかは興味深いところです。

Sebastian McKenzie(BabelやYarnを作った人)がRomeにフルタイムで入っている今、そのJavaScriptツールを統一しようとする試みはどこまで進むでしょうか。
コンパイル、テスト、Lint、その他全て、全てが入ったたったひとつの依存は完成するでしょうか。

我々は、フルスタックフレームワークであるRedwoodにも注目しています。
これはGraphQLと相性が良く、そしてデータハンドリングに"cells"と呼ばれるユニークな仕組みを使っています。

ユーザのフィードバックに基づいた、本調査とは別観点からの結果を見たいのであれば、State of JSも参照してください。

みてくれてありがとう。
また来年会いましょう!

感想

可及的速やかにReactが絶滅しますように。

このランキングが始まって以来4年間トップをひた走っていたVue.jsを抑えて、なんとDenoがトップに立ちました。
ただ、30kの半数近く13.7kは、バージョン1が出た5月の一ヶ月だけで稼いでいます。

01.png

ご祝儀にしても極端すぎるような。
試しに5月を除いてみると7位くらいです。
とはいえ非常に注目されていることには間違いないので、今後の技術の採用基準の視野に入れてもいいかもしれません。

ただし、あくまで☆の増加数であって、ダウンロード数でも実際に運用されているサイト数でもないので、注目されている=最適な技術である、は必ずしも成り立たないことに注意が必要です。
アーリーアダプター()以外の普通の開発者は、普通に枯れた技術を使うのが一番です。

たとえば昨年Angularを抜き去り、すわ新時代の到来かと思われたSvelteも、今年はあっさりAngularに抜き返されました。
Svelteが即座に消え去るとは思いませんが、今後RiotやAureliaのようにフェードアウトしていってもおかしくありません。
もちろん何かの拍子に再躍進する可能性もあるでしょう。
そのような将来が不安定な技術はそういうのが好きな連中に任せておいて、業務に取り入れるのは十分に成熟してからも遅くありません。
だいたいWebサイトを使うユーザは、そのサイトが何の技術でできているかなんて一切興味ありませんからね。
Next.js + TailwindだろうがjQuery + べた書きstyle要素だろうが、見た目が同じならそれは同じものです。

もちろん、そういうのが好きな人はどんどん手を出しましょう。
ちなみにこのJavaScript Rising StarsのサイトはNext.jsでできています。
コマンド幾つか打つだけでローカルサーバが立ち上がるのでとっても楽。
ただ昨年はホットリロード対応してたはずなんだけど今年は手動リロードしないとだめだった。なんでだろう?(調べてない)

Houkago Atelier Toiro ha iizo

02.png

半リモートワークを一年続けた感想

$
0
0

のっとふぉーみー。

私には合わなかった。

職種

よくあるIT系中小企業です。

私の部署は流行りのIoTとかいうやつで、主にB2Bで何か物体を売ったり売らなかったりサービスを提供したりしてなかったりします。
私は主にバックエンドのAzureまわりを担当していて、なんかデータを保存したりしなかったり出力したりしなかったりするのが主な仕事です。

仕事柄ハードウェアを直接触らなければならないことがあるため、完全フルリモートにすることはできません。
今はだいたい週2日程度出社しています。

会社について

会社の風通しはそれなりで、上司や社長にわりと色々直接言ったりもできます。
まあ社内でもそこそこ有能みたいな地位を確立できているみたいなのでそのせいかもしれないので、人に依るかもしれませんが。

対外的技術的にはあまりオープンではなく、キラキラインフルエンサーみたいな人もいないし、このQiitaでもおそらく社員の中で私一人しか記事を書いていません。
まあ私も社名を一切出してませんが。
そのへんあんまりベンチャーっぽくはない。
Facebookあたりでは会社で発信しているみたいですが、そちらは逆に私が未登録なので何やってるのかはわかりません。

リモートワークの導入

IT系の会社のわりに、元々はリモートワーク制度そのものがまともに機能していませんでした。
子育てなど一部例外のみ個別に許可するみたいなかんじで、実質的にはほぼ使われてない状態となっていました。
VPNも外出の多い営業人員のために部分的に導入されていたくらいで、全社員が接続すると即死する太さでした。

しかしこのご時世ということで、2020年の年明けしばらくして全社的に導入が決まりました。
社内にネットワーク部門があるだけあって、このあたりはさすがに動き出したら早かったです。
数週間でVPNが整備され、同時にリモートワーク制度も改訂され、あっという間に自由にリモートワークできるようになりました。

それから一年弱

それから一年弱が経ち、部署内でもリモートワークがだいぶ定着しました。
中には月数回しか出勤しない人もいます。
ただ、一切出勤しない完全フルリモートって人は部署内には今のところいません。
上述のとおり、仕事の性質上一切出勤しないのは難しいところなので、ここはまあ仕方ないですね。

会議は8割方Microsoft TeamsやZoomなどに移行しました。
ただ、やはり細かい調整とか詰めが必要なときは、直接会って話すこともまだまだあります。
細かいところってどうしてもリモート会議ではやりにくいのですが、そういうのみんなはどうしてるのでしょうか。

Pros

通勤時間がなくなる

片道1時間の通勤時間が完全になくなったのは実に大きいです。
毎日1時間も寝る時間が増えるのはよいことです。

ただ通勤時間はデレステに割り当てていたので、今年はデレステのプレイ時間が激減してしまい色々とたいへんでした。
秋頃にプロデュース方針が導入されたおかげで、後半はどうにかなりましたが。

自分用PCで作業できる

といってもディスプレイサイズとGPU1以外のスペックは会社支給PCのほうが上だったりするので、自分用PCだからこそ快適とかそんなことはわりとなかったりします。
私は開発環境構築マニアではないので自分用PCには開発ソフトウェアもろくに入っていませんし、仕事するだけであれば会社支給PCのほうが高効率です。

その他のメリット

一人暮らしなので家族との時間がみたいなのは特にありません。
家族がいる人にとってはここのメリットは非常に大きいものだと思います。
まあシャミ子セローの時間は増えた。

Cons

サボる

あらゆるメリットをぶっちぎる最大最強最低最悪のデメリットです。

私は趣味に使う金を稼ぐために仕方なく仕事しているだけなので、仕事に対するモチベーションとかそういうものは全くありません。
会社にいればサボるのもなかなか難しいので仕事もするのですが、監視の目がなくなったらどうなるかなんて火を見るより明らかです。

01.png

リモートワークの監視というと批判的な記事のほうが多く出てきますが、少なくとも私にとっては必要なものです。
まあ導入されてないので平日真っ昼間から焼肉行っちゃうわけですが。
肉うめえ。

運動不足

非常に深刻です。
目覚めてから寝るまで直径5メートルの範囲内しか動かないなんて事態もよくありますからね。
おかげでお腹周りとかたいへんなことに!

そんなわけで先日フィットボクシング2を導入しました。
2ヶ月弱続いてるので、今後もがんばっていきたいところです。

なお体重は減っていない模様。

デスク環境整備が必要

金も手間もかかりますね。
ええ、とても面倒です。

面倒なので整備を後回しにしたまま気付けばもう1年。
もうこのままでいいんじゃないかなあと思い始めている。


ちなみに左がPS4版、右がSteam版。

人が覚えられない

元々人の顔と名前を覚えるのが非常に苦手なのですが、リモートワークでさらに深刻になりました。
2020年4月に入った新卒の顔が未だにわかりません。
街中で話しかけられたら間違いなく(…誰だこいつ?)ってなります。

定期代が出なくなった

これまで通勤定期代が出ていたのですが、リモートワークが導入されてからは使った分だけ支払う方式にかわりました。
いまは定期を買って元が取れるほどは出勤していないので、休日に定期を使って出掛けたりとかができなくなりました。

気軽な相談とか雑談ができない

わからない疑問や質問などはほいほいSlackに投げる方なのですが、そこまでするほどでもないちょっとした会話とか、あるいは業務に全然関係ない雑談はなかなかし辛くなりました。

人との関わりが減った

上記とも関連しますが、単純に他人との接触が減ります。
まあ私はこの点は全く気にならないし、むしろ一人の方が楽まであるので平気なのですが、人によっては辛いかもしれませんね。

まとめ

自律心とか、向上心とか、責任感とか、そういったものをどれかひとつでも持っている人であれば、リモートワークのメリットを大いに享受することができるでしょう。

残念ながら私は何ひとつ持ち合わせていないので、会社という環境で仕方なく仕事しなければならない、という形のほうが性に合っています。
早くワクチンを打ってもらって、あと通勤時間さえどうにかなってくれれば、毎日通勤に戻りたいところですね。


  1. 会社支給PCは27インチ*2、内蔵GPU。自宅PCは32インチ*2、GTX1070。それ以外は全部会社支給PCのほうが上。 

何もしなくても運が悪いとApacheは落ちる

$
0
0

TL;DR

Apache2.4.26より前のauth_digest_moduleにはバグがあり、低確率でApacheが死ぬことがある。

経緯

ほぼ自分専用で他所からは誰も来ないWebサーバを数年運用しています。

運用というか放置ですが。
開設当初にある程度の設定を行いましたが、その後は何年も更新せずに、それどころかSSH接続することすらほとんどなくほったらかしでした。
私は環境構築マニアではないので、現在動いているサーバには何もしたくないのです。
セキュリティ?知らんな。

そんなでもこれまで数年間何の問題もなく動いていたのですが、なにやら先日突然Apacheが止まりました。

調査

とりあえずApacheのステータスを確認。

● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) 
     Docs: man:httpd(8)
           man:apachectl(8)
  Process: 123708 ExecStop=/bin/kill -WINCH${MAINPID}(code=exited, status=1/FAILURE)
  Process: 123702 ExecReload=/usr/sbin/httpd $OPTIONS-k graceful (code=exited, status=0/SUCCESS)
  Process: 32974 ExecStart=/usr/sbin/httpd $OPTIONS-DFOREGROUND(code=exited, status=1/FAILURE)
 Main PID: 32974 (code=exited, status=1/FAILURE)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec" 
 systemd[1]: Reloaded The Apache HTTP Server.
 systemd[1]: Reloaded The Apache HTTP Server.
 systemd[1]: Reloaded The Apache HTTP Server.
 systemd[1]: Reloaded The Apache HTTP Server.
 systemd[1]: Reloaded The Apache HTTP Server.
 systemd[1]: httpd.service: main process exited, code=exited, status=1/FAILURE
 kill[123456]: kill: cannot find process "" 
 systemd[1]: httpd.service: control process exited, code=exited status=1
 systemd[1]: Unit httpd.service entered failed state.
 systemd[1]: httpd.service failed.

止まってますね。
つぎにエラーログを確認。

# tail /var/log/httpd/error_log[auth_digest:notice] [pid 32768] AH01757: generating secret for digest authentication ...
[auth_digest:error] [pid 32768] (17)File exists: AH01762: Failed to create shared memory segment on file /run/httpd/authdigest_shm.32768
[auth_digest:error] [pid 32768] (17)File exists: AH01760: failed to initialize shm - all nonce-count checking, one-time nonces, and MD5-sess algorithm disabled
[:emerg] [pid 32974] AH00020: Configuration Failed, exiting

なんだこれは?
調べてみると、どうやらmod_auth_digestが共有メモリを作りに行ったけど、ファイルが既に存在していたのでエラーになりました、ということらしい。
そもそもダイジェスト認証なんて使ってないんだけど、LoadModuleで呼ばれているせいかな。
わざわざコンフィグファイルのシェイプアップなんてしてなかったと思うから、そのせいでしょう。

ipcsコマンドで共有メモリファイルを確認できます。

# ipcs------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 0          root       600        327680     6          dest
0x01234567 16777214   root       600        1000       0
…

ファイルが100個くらい並んでいました。
逆に言うと、たった100個程度でファイル名が被ってApacheが落ちるなんてのは明らかにおかしいでしょう。

というわけで調べてみたら8153365579e603ec0c50c7f2c27f4a06f927edddで修正されていました。
修正自体は2015/06/10に行われたみたいですが、それがマージされたのが何故か2年も経った2017/02/08で、そしてリリースされたのは2017/06/19のApache2.4.26のようです。

すなわち、それ以前のApacheには、低確率で脈絡なく突如Apacheが落ちる潜在的バグが潜んでいるということです。

原因

auth_digest_moduleは、apr_shm_createという関数を使って共有メモリファイルを生成しています。
このときに第三引数で対象のファイル名を与えているのですが、そのファイル名の生成方法がこれ。

client_shm_filename=ap_runtime_dir_relative(ctx,"authdigest_shm");client_shm_filename=ap_append_pid(ctx,client_shm_filename,".");

ap_append_pidは、テキストの後ろにpidをくっつけるという関数です。
pidはps -efとかで出てくるやつで、ランダム性など微塵もない概ね連番になってる数桁の数字です。
たとえば、PIDが32768であれば共有メモリファイル名はauthdigest_shm.32768になります。

まとめると、たまたま前回と同じPIDでmod_auth_digestが起動するとApacheが死にます。

おそらくはauth_digest_moduleの終了時に共有メモリファイルも削除するみたいな処理が入っていると思うのですが(確認してない)、何かの拍子にファイルが残ったままになってしまうことがあり、そのときに次のauth_digest_moduleが起動すると死ぬということのようです。

バグ修正

ファイル名にランダム要素を加えたりするのかと思いきやそうでもなく、単に共有メモリファイルを削除してから同じファイルを作り直すという原始的対応をやってました。
そんなんでいいのかよと思ったのですが、mod_luaやらutil_ldap_cacheやらも概ね同じ作りになっていて、どうやれこれで正しいみたいです。

対応

設定ファイルからLoadModule auth_digest_moduleを削除した。

アプデしろ?
知らんな。

感想

世界でもっとも有名なソフトウェアのひとつに、わりと最近までこんな致命的なバグが潜んでいたことにびっくりだよ。
しかもそのこのバグの存在自体がネット上にほぼ存在せず、それが修正されたという情報も全く見当たらないことに再度びっくりだよ。

日本語情報はほぼ見当たらず、わずかに存在する情報もせいぜい共有ファイルを削除したまでしか実施しておらず、根本的な解決まではしていないものばかりでした。
まあ英語でも質問に回答が全くついてないとか解決策が見当違いとかばっかりで、きちんと原因まで辿り着いてる資料はほとんどなかったのですが。

ところでApache2.5αに入ってるmod_nolorisにも今回とほぼ同じバグが入っているように見えるのですが、これは大丈夫なのだろうか?

その他

ipcrm -aでApacheを即座に落とせるぞ。

特に意味はないが。

【Chrome】『このページのQRコードを作成』を消す

$
0
0

何それ?

↓この邪魔な奴です。

01.png

方法

chrome://flags/#sharing-qr-code-generatorをURLにペーストして移動。
プルダウンを『Disabled』に変更。
再起動。

02.png

これでOKです。

PWAインストールボタンを消させろ

QRコードはまだ実害がさほど大きくないからいいのですが、隣にあるPWAインストールボタンは存在が害悪です。
しかも、かつては『Desktop PWAs installable from the omnibox』という設定から消すことができたのですが、消せなくしやがったクソが

Viewing all 338 articles
Browse latest View live