Php StreamContext何时可重用?什么时候不能重复使用?

Php StreamContext何时可重用?什么时候不能重复使用?,php,stream,Php,Stream,我正在从http传递到https,因此我必须将一个StreamContext添加到几个read\u file和get\u file\u contents调用中 我需要换一个 read_file('http://'.$host.$uri); 借 现在我的问题是:$stream\u上下文是否可以像这样重用: $stream_context = stream_context_create([ /* some lenghty options array */ ]); read_file('ht

我正在从http传递到https,因此我必须将一个
StreamContext
添加到几个
read\u file
get\u file\u contents
调用中

我需要换一个

read_file('http://'.$host.$uri);

现在我的问题是:$stream\u上下文是否可以像这样重用:

$stream_context = stream_context_create([
    /* some lenghty options array */
]);
read_file('https://'.$host.$uri, false, $stream_context);
get_file_contents($another_url, false, $stream_context);
read_file($even_another, false, $stream_context);
或者我需要为每个URL重新创建一个新的
StreamContext

以不同的方式询问:流上下文只是参数和选项的描述符,还是在使用它时会绑定到资源?

编辑:从评论中可以看出,可以经常重用
StreamContext
,但并不总是如此。这不是一个令人满意的答案


什么时候可以或者应该重用,什么时候不能重用?有人能解释一下
StreamContext
的内部工作原理吗。在我看来,这条路很稀疏。

看来你可以。我使用了
xdebug\u debug\zval
并运行了一些简单的测试,以查看PHP是否在内部保留它(我在内部开发服务器上使用了带有xdebug的PHP7.1.3)

我得到的是

背景:

(refcount=1,is_ref=0)资源(2,流上下文)

背景:

(refcount=1,is_ref=0)资源(2,流上下文)

背景:

(refcount=2,is_ref=0)资源(2,流上下文)

有趣的是,第二个调用增加了refcount,这意味着它是通过内部引用传递的。即使取消设置
$stream
也没有删除它或阻止我再次调用它

编辑 既然问题被修改了


上下文创建数据类型。因为它包含一个PHP数据实例,所以它是通过引用隐式传递的,这意味着PHP直接传递内部数据,而不是简单地复制它。没有破坏上下文的本机方法。

它显然用作连接对象(与数据库连接的逻辑相同),并且可以以类似的方式重用:

<?php
$default_opts = array(
  'http'=>array(
    'method'=>"GET",
    'header'=>"Accept-language: en\r\n" .
              "Cookie: foo=bar",
    'proxy'=>"tcp://10.54.1.39:8000"
  )
);


$alternate_opts = array(
  'http'=>array(
    'method'=>"POST",
    'header'=>"Content-type: application/x-www-form-urlencoded\r\n" .
              "Content-length: " . strlen("baz=bomb"),
    'content'=>"baz=bomb"
  )
);

$default = stream_context_get_default($default_opts);
$alternate = stream_context_create($alternate_opts);

/* Sends a regular GET request to proxy server at 10.54.1.39
 * For www.example.com using context options specified in $default_opts
 */
readfile('http://www.example.com');

/* Sends a POST request directly to www.example.com
 * Using context options specified in $alternate_opts
 */
readfile('http://www.example.com', false, $alternate);

?>

流上下文是可重用的,可以随时重复使用,而不是经常重复使用

@ilpaijin对“不可预测的行为评论”的评论只是对作者离开评论的误解

当您为HTTP包装器指定上下文时,您将包装器指定为HTTP,而不管您的目标模式是什么,这意味着不存在HTTPS包装器

如果您尝试执行以下操作:

"https" => [
// options will not be applied to HTTPS stream as there is no such wrapper (https)
]
正确的方法是:

"http" => [
// options will apply to http:// and https:// streams.
]
什么时候应该/可以重复使用?

这真的取决于你,取决于你试图实现的逻辑

别忘了你已经为所有人设置了默认上下文

您发布的示例中,相同的上下文流被传递给3个不同的调用,这是不必要的,只需简单使用,并为源于代码的请求设置默认上下文

在某些情况下,您可以设置默认值,但对于一个特定的请求,您希望具有不同的上下文,最好创建另一个流并将其传入

流上下文是否包含从一个调用传递到另一个调用的状态,例如cookie或tls初始协商?

流上下文不包含状态,但是您可以通过额外的代码实现这样的模拟。任何状态,不管是cookie还是TLS握手,都只是请求头。您需要从传入请求中读取该信息并在流中设置它,然后将该流传递给其他请求,从而模拟父请求的“状态”。也就是说,不要这样做,只要使用它


另一方面,流的真正力量是创造你自己的/习惯。使用CURL可以更容易(更好)地实现标题操作和状态控制。

我同意上述答案,stream\u context\u create()将通过获取连接的选项参数来创建并返回资源句柄。这可以重新用于不同的资源,因为它是一个句柄。不管它在哪里使用,但需要在请求中具有句柄。

您可以尝试一下。我希望它是可重用的,因为它是一种读而不写的资源;但似乎它可能会产生意想不到的结果(我想如果没有正确使用的话),正如这里所评论的:@ilpaijin这一点很有趣。一些上下文选项是特定于域的。我剩下的次要问题是:流上下文是否包含状态,例如cookies或tls初始协商是从一个呼叫传递到另一个呼叫?感谢您的回答。虽然它严格地回答了“是否是可重用的StreamContext”这个问题,但它并不是我所期望的。事实上,在某些情况下,它是不可重用的,比如当它涉及SSL连接时(请参阅注释)。我想更好地理解的是,在概念上什么才是真正的StreamContext。如何掌握它,而不仅仅是使用它。也许你应该分享
read\u file
的代码。我无法复制流上下文无法重用的情况。PHP函数通过引用传递它,因此它永远不会被破坏注意,问题是使用
read\u file
而不是
readfile
。这不是一个微不足道的区别是的的确。。。实际上我不知道什么是读取文件。我想说的是,上下文可能是自定义的,也可能是默认的。默认上下文可以在幕后多次使用。此外,上下文不需要关闭或循环使用。这应该意味着它们不会在请求之间收集任何状态。这是最好地阐述主题的问题。关于对的批评,我认为它没有抓住要点:
https
确实不是一个包装器名称,
tls
ssl
(同义词)是。我剩下的辅助问题是:流上下文是否包含状态,比如cookies或tls初始协商,它们从一个调用传递到另一个调用?H
"https" => [
// options will not be applied to HTTPS stream as there is no such wrapper (https)
]
"http" => [
// options will apply to http:// and https:// streams.
]