foreachの中で参照渡しのunsetしたときの不思議

PHPで、配列の中の特定の要素を削除するときといえばだいたい、
↓な感じかと思います。

<?php

$a = ['a' => 1, 'b' => 2, 'c' => 3];

foreach($a as $key => $val){
    if($val === 2){
        unset($a[$key]);
    }
}
array(2) {
  ["a"]=>
  int(1)
  ["c"]=>
  int(3)
}


けど、foreachで参照渡しができると知ったので、こんな書き方を試してみた。

<?php

$a = ['a' => 1, 'b' => 2, 'c' => 3];

foreach($a as &$val){
    if($val === 2){
        unset($val);
    }
}

しかし!!!!!!

array(3) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
  ["c"]=>
  &int(3)
}

消えてない!!!!

<?php

$a = ['a' => 1, 'b' => 2, 'c' => 3];

foreach($a as &$val){
    if($val === 2){
        unset($val);
    }
    $val = '^o^';
}

ただ、unsetのifブロックの外で代入すると、

array(3) {
  ["a"]=>
  string(3) "^o^"
  ["b"]=>
  int(2)
  ["c"]=>
  &string(3) "^o^"
}

unsetした要素以外には代入がされた。


なんでこうなるのか、詳しい人に聞いてもわからなかった…。
ストレートに考えると『unsetで参照が解除されただけ』ということなのだろうか。
分かる人教えてください…。

IDをkeyにした配列をarray_mergeしてバグを出しました

やったこと

<?php
$a = array('104' => 'a', '257' => 'b', '245' => 'c');
$b = array('477' => 'd', '502' => 'e', 'f4c' => '600');

var_dump(array_merge($a, $b)); // <1>
var_dump($a + $b); // <2>

けっか

<1>

array(6) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
  [4]=>
  string(1) "e"
  ["f4c"]=>
  string(3) "600"
}

<2>

array(6) {
  [100]=>
  string(1) "a"
  [200]=>
  string(1) "b"
  [300]=>
  string(1) "c"
  [400]=>
  string(1) "d"
  [500]=>
  string(1) "e"
  ["f4c"]=>
  string(3) "600"
}

既存に機能追加することになった。

array( key => array(データ) , ...)

な配列がもともとあったので、
同じ形式の配列をもう1つ作ってarray_mergeした。

結果、↑<1>の状態になってちゃんと読み込まれてないままリリースされ、土下座したtodayでした。

array_mergeはホント気をつけて使わねばならんという教訓。
ググると配列 + 配列も罠があるらしいことがわかったので、
確実に望んだ形の配列を得たいときは、

foreach(array as $key => $val)

で明示的に処理したほうがいい。



(テストデータに不備があってテスト環境で検出できなかったのも本当に悔しい。
 ってかテスト書けば検出できた。
 次はテスト書かないカルチャーの場所でもテスト書かせてもらうお願いをするなどしたい。)

OneSignalで特定ユーザーにプッシュを送るためのWeb実装

日本語の解説ページがあんまり見当たらなかった…。

 
OneSignalはプッシュ通知を購読登録されたとき、ユーザーを識別するOneSignal player IDなるものを払い出します。
このPlayer IDを指定して通知を飛ばすと、特定のユーザーだけに送ることができます。
このPlayer IDと他の情報を結びつけて、パーソナライズされた通知を送る実装方法のメモです。
Webでの実装方法なのでJavaScriptを扱ってますが、自分はぜんぜんJavaScriptできないのでどうかご容赦!!

初期登録までは↓が大変参考になりました。
qiita.com
 

☆やりかた☆

 1.スニペットを仕込む
OneSignalを登録したときにheadタグ内に貼ってねっていわれたやつを言われたとおりにペースト。

<link rel="manifest" href="/manifest.json" />
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
<script>
  var OneSignal = window.OneSignal || [];
  OneSignal.push(function() {
    OneSignal.init({
      appId: "<アプリIDここにいれてね>",
    });
  });
</script>

 
ここからはOneSignalのWeb Push SDKのページもみよう!
documentation.onesignal.com

 

2.通知許可状態変更イベントを仕込む
https://documentation.onesignal.com/docs/web-push-sdk#section-callback-event-parameters

OneSignal.push(function() {
  // Occurs when the user's subscription changes to a new value.
  OneSignal.on('subscriptionChange', function (isSubscribed) {
    console.log("The user's subscription state is now:", isSubscribed);
  });
});

subscriptionChangeは、ブラウザの通知許可状態が変化すると発火します。
isSubscribedには許可状態がbooleanで入ります。

許可=true
拒否=false

このイベントは受信拒否されたときにも発火しますので注意。許可されたら発火でゎない。
 

3.Player IDを取得する
https://documentation.onesignal.com/docs/web-push-sdk#section--getuserid-

  OneSignal.getUserId(function(userId) {
    console.log("OneSignal User ID:", userId);
  });

OneSignal.getUserId()でPlayer IDが取得できます。
(User IDっていったりPlayer IDっていったり、公式の呼び方が定まらなくて混乱した)
このIDを自サーバーのAPIなんかに投げてやればOK。
あとはサーバー側でうまくやって他の情報と紐つけましょう。

 

2と3を混ぜるとこんなかんじ。

OneSignal.push(function() {
  // Occurs when the user's subscription changes to a new value.
  OneSignal.on('subscriptionChange', function (isSubscribed) {
    if (isSubscribed) {
      OneSignal.getUserId(function(userId) {
        // ここでAPIとか叩く!!!!
      });
    }
  });
});

 
4.Player IDをターゲティングしてプッシュ通知を送信する

公式に実装サンプルがあるのでこちらをどうぞ。
documentation.onesignal.com

OneSignalは驚くほどにわかりやすい。
PWAとかService Workerとか、高い壁をガンガン叩き壊してくれますね…。
生きやすい世界万歳🙏🙏🙏🙏🙏

ちなみにプッシュ送信のときには、
Segment Tags UserIDのいずれかから1つ指定して送信できます。
複数指定するっていうアホなことをやって軽く詰んだ(みんなに届くジャン・・・)のですが、
Tags < Segment < UserID
の順で優先されるようです。
 

 

 

IFTTTのWebhooksの作成方法

地味に分かり辛いよね。

 

IFTTTのWebhookは他のアプリケーションと同じページから設定ができません。
なので、設定のためにIFTTT Platformにサインインする必要があります。
(アカウントはIFTTTと共通です。)

 

手順

①IFTTT Platformにサインイン
https://platform.ifttt.com/


②画面右上の「Dashboard」を選択
f:id:komajou:20180323211218j:image


③画面右の青いボタン「New Applet」を選択
f:id:komajou:20180323211241j:image


④トリガーに「Webhooks」を選択
f:id:komajou:20180323211327j:image


⑤Webhooksを選択したらその下のリストから「Receive a web request」を選択して、
 イベント名を入力
f:id:komajou:20180323211354j:image


⑥thenで連携先サービスを選択


f:id:komajou:20180323211419j:image

今回はLINEを選択したので、受け取りたいメッセージになるように入力します。
f:id:komajou:20180323211443j:image


⑦できたらページ最下部の「Save」を押下

 

⑧自分のリクエストURLをチェック
https://ifttt.com/services/maker_webhooks/settings
↑ここから確認可能

 

⑨URLを叩いて期待挙動ができたら完成。