PHP file_get_contents和curl区别

一、file_get_contents

1.定义

file_get_contents() 函数将指定 URL 的文件读入一个字符串并返回。

2.语法

file_get_contents(path, include_path, context, start, max_length)
  • path:要读取的路径或链接。
  • include_path:是否在路径中搜索文件,搜索则设为 1,默认为 false。
  • context:修改流的行为,如超时时间,GET / POST 等。
  • start:开始读文件的位置。
  • max_length:读取文件的字节数。

3.示例

test.txt

<?php
echo "i'm a test php";
?>

index.php

<?php
$testTxt = file_get_contents('./test.txt');
var_dump($testTxt); // string(15) "i'm a test txt."

$ctx = stream_context_create(
    array(
        'http' => array(
            'method' => 'get',
            'timeout' => 30
        )
    )
);
$testTxt = file_get_contents('./test.txt', false, $ctx, 4, 6);
var_dump($testTxt); // string(6) "a test"
?>

二、curl

1.定义

PHP 支持 Daniel Stenberg 创建的 libcurl 库,能够连接通讯各种服务器、使用各种协议。libcurl 目前支持的协议有 http、https、ftp、gopher、telnet、dict、file、ldap。 libcurl 同时支持 HTTPS 证书、HTTP POST、HTTP PUT、 FTP 上传(也能通过 PHP 的 FTP 扩展完成)、HTTP 基于表单的上传、代理、cookies、用户名+密码的认证。

2.语法

  1. curl_init:初始化 cURL 会话。
  2. curl_setopt:设置 cURL 传输选项。
  3. curl_exec:返回 true / false,curl_setopt 设置 CURLOPT_RETURNTRANSFER 为 TRUE 时将 curl_exec() 获取的信息以字符串返回。
  4. curl_close:关闭 cURL 会话。

3.示例

test.php

<?php
echo "i'm a test php";
?>

index.php

<?php
// 创建一个新 cURL 资源
$ch = curl_init();

// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, "http://localhost/test.php"); // 需要获取的 URL 地址,也可以在 curl_init() 初始化会话的时候。
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HEADER, false); // 启用时会将头文件的信息作为数据流输出。
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 在尝试连接时等待的秒数。设置为 0,则无限等待。
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 允许 cURL 函数执行的最长秒数。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // TRUE 将 curl_exec() 获取的信息以字符串返回,而不是直接输出。

// 抓取 URL 并把它传递给浏览器
$ret = curl_exec($ch);

var_dump($ret);

// 关闭 cURL 资源,并且释放系统资源
curl_close($ch);
?>

三、file_get_contents 和 curl 区别

1.curl 支持更多功能

curl 支持更多协议,有http、https、ftp、gopher、telnet、dict、file、ldap;模拟 Cookie 登录,爬取网页;FTP 上传下载。

fopen / file_get_contents 只能使用 GET 方式获取数据。

2.性能

curl 可以进行 DNS 缓存,同一个域名下的图片或其它资源只需要进行一次DNS查询。

curl 相对来说更加快速稳定,访问量高的时候首选 curl,缺点就是相对于 file_get_contents 配置繁琐一点,file_get_contents 适用与处理小访问的应用。

浮动元素引起的问题和解决办法

一、问题

  1. 多个浮动的元素无法撑开父元素的宽度,父元素的高度可能会变成0。
  2. 若浮动元素后面跟非浮动元素,非浮动元素会紧随其后浮动起来。
  3. 若浮动元素前面还有同级元素没有浮动则会影响页面结构。

二、解决办法

1.clear:both

在最后一个浮动元素后面添加属性为clear:both;的元素。

<style>
div.parent>div.fl{
    float: left;
    width: 200px;
    height: 200px;
    margin-right: 20px;
    border: 1px solid red;
}
.clear{
    clear: both;
}
</style>
<div class="parent">
    <div class="fl">1</div>
    <div class="fl">2</div>
    <div class="fl">3</div>
    <div class="fl">4</div>
    <div class="clear">5</div>
</div>

给父元素添加clear:both;属性的:after伪元素。

<style>
div.parent>div.fl{
    float: left;
    width: 200px;
    height: 200px;
    margin-right: 20px;
    border: 1px solid red;
}
.clear:after{
    content: '';
    display: block;
    clear: both;
}
</style>
<div class="parent clear">
    <div class="fl">1</div>
    <div class="fl">2</div>
    <div class="fl">3</div>
    <div class="fl">4</div>
</div>
注意:伪元素默认是内联水平,所以借助伪元素时要设置属性display: block;

2.overflow:auto / overflow: hidden

<style>
div.parent{
    overflow: auto;
    /*overflow: hidden;也可以*/
}
div.parent>div.fl{
    float: left;
    width: 200px;
    height: 200px;
    margin-right: 20px;
    border: 1px solid red;
}
</style>
<div class="parent">
    <div class="fl">1</div>
    <div class="fl">2</div>
    <div class="fl">3</div>
    <div class="fl">4</div>
</div>

3.浮动父级元素

<style>
div.parent{
    float: left;
}
div.parent>div.fl{
    float: left;
    width: 200px;
    height: 200px;
    margin-right: 20px;
    border: 1px solid red;
}
</style>
<div class="parent">
    <div class="fl">1</div>
    <div class="fl">2</div>
    <div class="fl">3</div>
    <div class="fl">4</div>
</div>
注意:一般不用这个方法,会引起父级元素排版问题。

PHP 神奇的sprintf函数

sprintf

1.定义

sprintf() 函数将字符串进行各种类型的格式化。

2.语法

sprintf(format,arg1,arg2,arg++)
  • format:格式类型。
  • arg1,arg2,arg++:需要被查到被格式化字符串中的1到若干个参数。

format参照表

format 说明
%% 返回一个百分号 %
%b 二进制数
%c ASCII 值对应的字符
%d 包含正负号的十进制数(负数、0、正数)
%e 使用小写的科学计数法(例如 1.2e+2)
%E 使用大写的科学计数法(例如 1.2E+2)
%u 不包含正负号的十进制数(大于等于 0)
%f 浮点数(本地设置)
%F 浮点数(非本地设置)
%g 较短的 %e 和 %f
%G 较短的 %E 和 %f
%o 八进制数
%s 字符串
%x 十六进制数(小写字母)
%X 十六进制数(大写字母)

附加的格式值,必需放置在 % 和字母之间(例如 %.2f)。

  • +(在数字前面加上 + 或 – 来定义数字的正负性。默认情况下,只有负数才做标记,正数不做标记)
  • '(规定使用什么作为填充,默认是空格。它必须与宽度指定器一起使用。例如:%'x20s(使用 "x" 作为填充))
  • -(左调整变量值)
  • [0-9](规定变量值的最小宽度)
  • .[0-9](规定小数位数或最大字符串长度)

3.示例

3.1将1补位成为001。

$num = 1;
$spf = sprintf("%'03d", $num); // '后面是0表示用0补位,3是新字符串宽度
var_dump($spf); // string(3) "001"

3.2总宽度为3且只保留2位,并用[]括起来。

$str = '12345';
$spf = sprintf("[%3.2s]", $str); // 3表示宽度为3,宽度不足左边补位,若-3则右边补位;.2表示从左往右取两位。
var_dump($spf); // string(5) "[ 12]" 默认空格补位,空格补位再多只显示一个空格。

关于this,作用域,属性,原型链的一个小练习

function p () {
    this.name = 'x';
    var name = 'y';
    this.getName = function () {
        return name;
    }
}
// 求值
console.log(new p().getName());

getName方法里面返回name值,此时name值从作用域里面找,即var name = 'y';,返回y;
将getName方法里面的return name;改成return this.name;,这时会从this里面找属性为name的值,即'this.name = 'x';',返回x(之前一直觉得this取决于定义环境,而不取决于执行环境,后来得到一种说法是this取决于调用环境,包括方法调用、函数调用、构造器调用和apply/call调用,其实这边的调用和定义是一个意思,比如上面的this便是构造器调用)。

function p () {
//    this.name = 'x';
//    var name = 'y';
    this.getName = function () {
        return this.name;
    }
}
p.prototype.name = 'z';
// 求值
console.log(new p().getName());

若找不到属性便会在原型链上找name,即p.prototype.name = 'z';,返回z。

for…of 与 for…in 区别

一、for…of

1.定义

for…of 语句遍历可迭代对象(包括数组、Set 和 Map 结构、arguments 对象、DOM NodeList 对象、字符串等)。

2.语法

for (variable of iterable) {
    //statements
}

3.示例

<ul>
    <li>mazey</li>
    <li>luna</li>
    <li>cherrie</li>
</ul>
<script>
// 数组
let arr = ['mazey', 'luna', 'cherrie'];
for (let v of arr) {
    console.log(v);
}
// mazey luna cherrie

// 字符串
let str = 'mlc';
for (let v of str) {
    console.log(v);
}
// m l c

// 类数组对象
let obj = {
    0: 'mazey',
    1: 'luna',
    2: 'cherrie',
    length: 3
};
// 需使用Array.from转换成可迭代对象
for (let v of Array.from(obj)) {
    console.log(v);
}
// mazey luna cherrie

// Set
let s = new Set(['mazey', 'luna', 'cherrie']);
for (let v of s) {
    console.log(v);
}
// mazey luna cherrie

// Map
let m = new Map([
    ['name0', 'mazey'],
    ['name1', 'luna'],
    ['name2', 'cherrie']
]);
for (let [i, v] of m) {
    console.log(v);
}
// mazey luna cherrie

// DOM NodeList
let domList = document.querySelectorAll('li');
for (let v of domList) {
    console.log(v.innerText);
}
// mazey luna cherrie
</script>

二、for…of 与 for…in 区别

1.for…in 遍历键名,for…of 遍历键值

let arr = ['mazey', 'luna', 'cherrie'];
for (let k in arr) {
    console.log(k);
}
// 0 1 2
for (let v of arr) {
    console.log(v);
}
// mazey luna cherrie

2.for…in 会把对象上手动添加的属性和原型上的属性暴露出来

let obj = {
    0: 'mazey',
    1: 'luna',
    2: 'cherrie',
    length: 3
};
obj.name = 'objName';
for (let k in obj) {
    console.log(k);
}
// 0 1 2 length name
for (let v of Array.from(obj)) {
    console.log(v);
}
// mazey luna cherrie

三、for…of 其它优点

1.相对于数组自带的 forEach 方法,for…of 可以与 break、continue 和 return 配合使用。
2.正确识别32位 UTF-16 字符。

JavaScript理解(object.getName = object.getName)()这段代码

var name = "The Window";
var object = {
    name : "My Object",
    getName: function(){
         return this.name;
    }
};
(object.getName = object.getName)(); // The Window

我的理解是:
this取决于定义环境而不取决于执行环境。

在这里

(object.getName = object.getName)();

相当于

(object.getName = function () {
    return this.name;
})();

// 拆分开来看
function () {
    return this.name;
}
// 这里的this = window
// 然后window.name在前面已经定义过了 var name = "The Window"; 定义全局变量
// 所以实际上执行的是
(function () {
     return this.name;
 })(); // The Window

ES6 Promise对象then方法链式调用

then()方法的作用是Promise实例添加解决(fulfillment)和拒绝(rejection)状态的回调函数。then()方法会返回一个的Promise实例,所以then()方法后面可以继续跟另一个then()方法进行链式调用。

let p = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'success');
});
p.then(
    res => {
        console.log(res);
        return `${res} again`;
    }
)
    .then(
        res => console.log(res)
    );
// 连续
// success
// success again

但是前一个then()方法中的回调函数中又可能返回一个Promise实例,这时候后面一个then()方法中的回调函数会等前一个Promise实例的状态发生变化才会调用。

let p = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 'success');
});
p.then(
    res => {
        console.log(res);
        return new Promise((resolve, reject) => {
            setTimeout(resolve, 1000, 'success');
        });
    }
)
    .then(
        res => console.log(res)
    );
// 相隔1000ms
// success
// success

ES6通过WeakMap解决内存泄漏问题

一、Map

1.定义

Map对象保存键值对,类似于数据结构字典;与传统上的对象只能用字符串当键不同,Map对象可以使用任意值当键。

2.语法

new Map([iterable])

属性

  • size:返回键值对的数量。

操作方法

  • set(key, value):设置(新增/更新)键key的值为value,返回Map对象。
  • get(key):读取键key的值,没有则返回undefined。
  • has(key):判断一个Map对象中是否存在某个键值对,返回true/false。
  • delete(key):删除某个键值对,返回true/false。
  • clear():清除Map对象中所有键值对。

遍历方法

  • keys():返回键名的Iterator对象。
  • values():返回键值的Iterator对象。
  • entries():返回键值对的Iterator对象。
  • forEach((value, key, map) => {}):遍历Map对象所有键值对。

3.示例

操作方法

let m = new Map([
    ['foo', 11],
    ['bar', 22]
]);
m.set('mazey', 322)
    .set('mazey', 413);
console.log(m); // {"foo" => 11, "bar" => 22, "mazey" => 413}
console.log(m.has('mazey')); // true
m.delete('mazey');
console.log(m.has('mazey')); // false
m.clear();
console.log(m); // {}

遍历方法

let m = new Map([
    ['foo', 11],
    ['bar', 22],
    ['mazey', 413]
]);
console.log(m); // {"foo" => 11, "bar" => 22, "mazey" => 413}
console.log(m.keys()); // MapIterator {"foo", "bar", "mazey"}
console.log(m.values()); // MapIterator {11, 22, 413}
console.log(m.entries()); // MapIterator {"foo" => 11, "bar" => 22, "mazey" => 413}
m.forEach((value, key, map) => {
    console.log("键:%s,值:%s", key, value);
});
// 键:foo,值:11
// 键:bar,值:22
// 键:mazey,值:413

二、WeakMap

1.定义

WeakMap对象保存键值对,与Map不同的是其键必须是对象,因为键是弱引用,在键对象消失后自动释放内存。

2.语法

new WeakMap([iterable])

方法

  • set(key, value):设置(新增/更新)键key的值为value,返回WeakMap对象。
  • get(key):读取键key的值,没有则返回undefined。
  • has(key):判断一个WeakMap对象中是否存在某个键值对,返回true/false。
  • delete(key):删除某个键值对,返回true/false。
注意

因为WeakMap的特殊的垃圾回收机制,所以没有clear()方法。

3.示例

let obj = {
    foo: 11
};
let wm = new WeakMap();
wm.set(obj, 413322);
console.log(wm); // {{…} => 413322}
console.log(wm.has(obj)); // true

三、通过WeakMap解决内存泄漏问题

当使用Dom对象绑定事件时,Dom对象消失后若没有及时释放内存(置null),便会一直存在内存中。
使用WeakMap保存Dom对象不会出现这样的问题,因为Dom对象消失后,JS的垃圾回收机制便会自动释放其所占用的内存。

<button type="button" id="btn">按钮</button>
<script>
let wm = new WeakMap();
let btn = document.querySelector('#btn');
wm.set(btn, {count: 0});
btn.addEventListener('click', () => {
    let v = wm.get(btn);
    v.count++;
    console.log(wm.get(btn).count);
});
// 1 2 3 4 5...
</script>

ES6通过Set数组去重

一、Set

1.定义

Set对象是ES6中新定义的数据结构,类似于数组,它允许你存储任何类型的唯一值,不管是原始值还是对象引用。

2.语法

new Set([iterable])
  • iterable:可迭代对象,默认为空。

Set方法

  • add:添加值,返回Set本身。
  • delete:删除值,返回是否删除成功。
  • has:判断是否拥有这个值,返回true/false。
  • clear:清除所有值。

3.示例

let s = new Set();
s.add(4);
s.add(1);
s.add(3);
s.add(3);
s.add(2);
s.add(2);
console.log(s); // {4, 1, 3, 2}
console.log(s.has(4)); // true
s.delete(4);
console.log(s); // {1, 3, 2}
console.log(s.has(4)); // false
s.clear();
console.log(s); // {}

二、通过Set数组去重

利用扩展运算符可以将Set转换成真正意义上的数组。

let arr = [4, 1, 3, 3, 2, '2'];
let uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [4, 1, 3, 2, "2"]

JavaScript启示录 – Cody Lindley 著 / 徐涛 译

核心知识点基本都讲了,JavaScript入门的话是很好的一本书。

2014年3月第1版

Function()参数

Function()构造函数采用不定数量的参数,但Function()构造函数的最后一个参数是一个包含具有函数体语句的字符串。在最后一个参数之前传递给构造函数的任何参数都可用于创建的函数。也可以将多个参数放在一起以逗号分隔形成字符串进行传递。

let add = new Function('a', 'b', 'return a + b');
// 等于
let add = new Function('a, b', 'return a + b');
// 等于
let add = function (a, b) {
    return a + b;
};
// 等于
function add (a, b) {
    return a + b;
}

arguments.callee属性

arguments对象拥有名为callee的属性,它是对当前执行函数的引用。该属性可以用于从函数的作用域内引用函数(如arguments.callee) – 自我引用(严格模式use strict;不能使用)。当函数需要递归调用时,它非常有用。

function SumNum (num) {
    if (num === 1) {
        return num
    }
    return num + arguments.callee(--num);
}
console.log(SumNum(5)); // 15

// 尾递归
function SumNumTail (num, total) { // total = 0 设置默认值会报错,因为严格模式不能使用arguments.callee
    if (num === 1) {
        return total + 1;
    }
    total += num
    return arguments.callee(--num, total);
}
console.log(SumNumTail(5, 0)); // 15

可以通过利用callee属性获得长度值,即arguments.callee.length。

自调用的匿名函数语句

自调用的匿名函数语句。

(function (msg) {
    console.log(msg);
})('Hello, 2018!'); // Hello, 2018!
// 等于
(function (msg) {
    console.log(msg);
}('Hello, 2018!')); // Hello, 2018!
// 等于
!function (msg) {
    console.log(msg);
}('Hello, 2018!'); // Hello, 2018!

创建继承连

设计原型继承的目的是要在传统的面向对象编程语言中找到模仿继承模式的继承链。继承只是一个对象可以访问另外一个对象的属性。具体做法是,实例化想要继承的对象,将该对象实例作为要继承该对象实例的函数的prototype属性。完成之后,对象之间有一个链接(也称为proto),可以通过属性查找将可用属性扩展至对象。

function f0 () {}
function f1 () {}
f1.prototype = new f0();
console.log(f1.prototype.__proto__ === f0.prototype); // true