热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

node.js中模块_您应该在Node.js中了解有关“模块”和“需求”的所有信息

node.js中模块bySrishtiGupta通过SrishtiGupta您应该在Node.js中了解有关模块和需求的所有信息(Everythingyoushouldknowab

node.js中模块

by Srishti Gupta

通过Srishti Gupta

您应该在Node.js中了解有关`` 模块''和``需求''的所有信息 (Everything you should know about ‘module’ & ‘require’ in Node.js)

模组 (Modules)

Node.js treats each Javascript file as a separate module.
Node.js将每个Javascript文件视为一个单独的模块。

For instance, if you have a file containing some code and this file is named xyz.js, then this file is treated as a module in Node, and you can say that you’ve created a module named xyz.

例如,如果您有一个包含一些代码的文件,并且此文件名为xyz.js ,则此文件在Node中被视为模块 ,可以说您已经创建了一个名为xyz的模块。

Let’s take an example to understand this better.

让我们举个例子来更好地理解这一点。

You have a file named circle.js which consists of the logic for calculating the area & the circumference of a circle of a given radius, as given below:

您有一个名为circle.js的文件,该文件包含用于计算给定半径的圆的面积和周长的逻辑,如下所示:

circle.js

circle.js

You can call circle.js file a module named circle.

您可以将circle.js文件称为一个名为circle的模块。

You might be wondering why is there a need to have multiple modules? You could have just written all the code in a single module. Well, it is very important to write modular code. By modular, I mean to say that your code should be independent and should be loosely coupled. Imagine that there’s a large application and you have all your code written in just one place, just one file. Too messy, right?

您可能想知道为什么需要多个模块? 您可能已经在一个模块中编写了所有代码。 好吧,编写模块化代码非常重要。 模块化,我的意思是说您的代码应该独立并且应该松散耦合。 想象一下,有一个大型应用程序,而您所有的代码都只写在一个地方,只有一个文件。 太乱了吧?

编写在模块内部的代码如何运行? (How does the code written inside a module run?)

Before executing the code written inside a module, Node takes the entire code and encloses it within a function wrapper. The syntax of this function wrapper is:

在执行写在模块内部的代码之前,Node将全部代码封装在函数包装器中。 该函数包装的语法为:

The function wrapper for the circle module will look like the one given below:

circle模块的功能包装器将如下所示:

You can see that there is a function wrapper at the root level encompassing all the code written inside the circle module.

您会看到在根级别有一个函数包装器,其中包含在circle模块中编写的所有代码。

The entire code written inside a module is private to the module, unless explicitly stated (exported) otherwise.
除非另有明确说明(导出),否则模块内部编写的全部代码均为该模块专用。

This is the most significant advantage of having modules in Node.js. Even if you define a global variable in a module using var, let or const keywords, the variables are scoped locally to the module rather than being scoped globally. This happens because each module has a function wrapper of its own and the code written inside one function is local to that function and cannot be accessed outside this function.

这是在Node.js中拥有模块的最大优势。 即使您使用var , letconst关键字在模块中定义了全局变量,变量也只在模块本地作用域,而不是全局范围。 发生这种情况是因为每个模块都有自己的函数包装器,并且在一个函数内部编写的代码是该函数的本地代码,无法在该函数外部访问。

Imagine that there are two modules — A and B. The code written inside the module A is enclosed within the function wrapper corresponding to the module A. Similar thing happens with the code written inside the module B. Because the code pertaining to both the modules is enclosed within different functions, these functions will not be able to access the code of each other. (Remember each function in Javascript has its own local scope?) This is the reason why module A cannot access the code written inside module B and vice-versa.

想象有两个模块-AB。 写入模块A内的代码被封装在对应于模块A的函数包装器中。 在模块B内编写的代码也会发生类似的情况。 由于与两个模块有关的代码包含在不同的功能内,因此这些功能将无法相互访问代码。 (还记得Javascript中的每个函数都有自己的局部作用域吗?)这就是模块A无法访问模块B内编写的代码的原因,反之亦然。

The five parameters — exports, require, module, __filename, __dirname are available inside each module in Node. Though these parameters are global to the code within a module yet they are local to the module (because of the function wrapper as explained above). These parameters provide valuable information related to a module.

五个参数- exports , require , module , __filename , __dirname可在每个节点模块内。 尽管这些参数对于模块内的代码是全局的,但它们对于模块而言是局部的(由于上述函数包装器)。 这些参数提供与模块有关的有价值的信息。

Let’s revisit the circle module, which you looked at earlier. There are three constructs defined in this module — a constant variable PI, a function named calculateArea and another function named calculateCircumference. An important point to keep in mind is that all these constructs are private to the circle module by default. It means that you cannot use these constructs in any other module unless explicitly specified.

让我们重新访问您之前看过的circle模块。 在此模块中定义了三个构造-常数变量PI ,一个名为calculateArea的函数和另一个名为calculateCircumference函数。 要记住的重要一点是,默认情况下,所有这些构造都是circle模块专用的。 这意味着除非明确指定,否则您不能在任何其他模块中使用这些构造。

So, the question that arises now is how do you specify something in a module that can be used by some other module? This is when the module & require parameters of the function wrapper are helpful. Let’s discuss these two parameters in this article.

因此,现在出现的问题是如何在模块中指定可以被其他模块使用的内容? 这是当函数包装的modulerequire参数有用时。 让我们在本文中讨论这两个参数。

module (module)

The module parameter (rather a keyword in a module in Node) refers to the object representing the current module. exports is a key of the module object, the corresponding value of which is an object. The default value of module.exports object is {} (empty object). You can check this by logging the value of module keyword inside any module. Let’s check what is the value of module parameter inside the circle module.

module参数(而是Node中模块中的关键字)是表示当前模块的对象。 exportsmodule对象的键, module对象的对应值是一个对象。 module.exports对象的默认值为{} (空对象)。 您可以通过在任何模块内记录module关键字的值来检查此情况。 让我们检查一下circle模块中module参数的值是多少。

circle.js

circle.js

Notice that there is a console.log(module); statement at the end of the code in the file given above. When you see the output, it will log the module object, which has a key named exports and the value corresponding to this key is {} (an empty object).

注意,有一个console.log(module); 上面给出的文件中代码末尾的语句。 当您看到输出时,它将记录module对象,该对象具有名为exports的键,并且与该键对应的值为{} (空对象)。

Now, what does the module.exports object do? Well, it is used for defining stuff that can be exported by a module. Whatever is exported from a module can, in turn, be made available to other modules. Exporting something is quite easy. You just need to add it to the module.exports object. There are three ways to add something to the module.exports object to be exported. Let’s discuss these methods one by one.

现在, module.exports对象做什么? 好吧,它用于定义可以由模块导出的内容。 反过来,从模块导出的所有内容都可以提供给其他模块。 导出内容非常容易。 您只需要将其添加到module.exports对象即可。 有三种方法可以将某些内容添加到要导出的module.exports对象中。 让我们一一讨论这些方法。

Method 1:(Defining constructs and then using multiple module.exports statements to add properties)

方法1 :( 定义构造,然后使用多个module.exports语句添加属性)

In the first method, you define the constructs first and then use multiple module.exports statements where each statement is used to export something from a module. Let’s look at this method in action and see how you can export the two functions defined in the circle module.

在第一种方法中,首先定义结构,然后使用多个module.exports语句,其中每个语句用于从模块中导出内容。 让我们看一下实际使用的此方法,看看如何导出在circle模块中定义的两个函数。

circle.js

circle.js

As I told you earlier, module is an object having the key named exports and this key (module.exports), in turn, consists of another object. Now, if you notice the code given above, all you are doing is adding new properties (key-value pairs) to the module.exports object.

正如我告诉你之前, module是具有名为key对象exports ,并且这个键( module.exports ),反过来,由另一个对象。 现在,如果您注意到上面给出的代码,您正在做的就是向module.exports对象添加新属性(键值对)。

The first property has the key calculateArea (defined on line 19) and the value written on the right side of the assignment operator is the function defined with the name calculateArea (on line 9).

第一个属性具有键calculateArea (在第19行定义) 并且写在赋值运算符右侧的值是使用名称calculateArea定义的函数(第9行)。

The second property (defined on line 20) has the key calculateCircumference and the value is the function defined with the name calculateCircumference (on line 16).

第二个属性(在第20行定义)的键为calculateCircumference 该值是使用名称calculateCircumference定义的函数(第16行)。

Thus, you have assigned two properties (key-value pairs) to the module.exports object.

因此,您已为module.exports对象分配了两个属性(键-值对)。

Also, let’s not forget that you have used the dot notation here. You can alternatively use the bracket notation for assigning the properties to the module.exports object and add the functions — calculateArea and calculateCircumference by specifying the keys following the bracket notation. Thus, you can write the following two lines to add properties to the module.exports object using bracket notation while replacing the last two lines (using dot notation) in the code given above:

另外,请不要忘记您在此处使用了点符号。 可以替代地使用括号标记用于分配属性到module.exports对象并添加功能- calculateAreacalculateCircumference通过指定以下的括号符号的键。 因此,您可以编写以下两行以使用括号表示法将属性添加到module.exports对象,同时替换上面给出的代码中的最后两行(使用点表示法):

// exporting stuff by adding to module.exports object using the bracket notation

module.exports['calculateArea'] = calculateArea;module.exports['calculateCircumference'] = calculateCircumference;

Let’s now try to log the value of the module.exports object after adding the properties. Notice that the following statement is added at the end of the code in the file given below:

现在,让我们尝试在添加属性后记录module.exports对象的值。 请注意,以下语句添加在下面给出的文件中代码的末尾:

// logging the contents of module.exports object after adding properties to it

console.log(module.exports);

circle.js

circle.js

Let’s check the output of this code and see if everything is working fine. To do this, save your code and run the following command in your Terminal:

让我们检查一下此代码的输出,看看一切是否正常。 为此,请保存代码并在终端中运行以下命令:

node circle

Output:

输出:

{ calculateArea: [Function: calculateArea], calculateCircumference: [Function: calculateCircumference] }

The constructs — calculateArea and calculateCircumference, added to the module.exports, object are logged. Thus, you successfully added the two properties in the module.exports object so that the functions — calculateArea and calculateCircumference can be exported from the circle module to some other module.

该构造- calculateAreacalculateCircumference ,加入到module.exports ,对象被记录。 因此,你成功添加在两个属性module.exports对象,以使功能- calculateAreacalculateCircumference可以从导出circle模块到其他模块。

In this method, you first defined all the constructs and then used multiple module.exports statements where each statement is used to add a property to the module.exports object.

在此方法中,您首先定义了所有构造,然后使用了多个module.exports语句,其中每个语句用于向module.exports对象添加属性。

Method 2:(Defining constructs and then using a single module.exports statement to add properties)

方法2 :( 定义构造,然后使用单个module.exports语句添加属性)

Another way is to define all the constructs first (as you did in the earlier method) but use a single module.exports statement to export them all. This method is similar to the syntax of object literal notation where you add all the properties to an object at once.

另一种方法是先定义所有构造(就像您在前面的方法中所做的那样),但是使用单个module.exports语句将它们全部导出。 此方法类似于对象文字符号的语法,在该语法中,您一次将所有属性添加到对象。

Here, you used the object literal notation and added both the functions — calculateArea and calculateCircumference (all at once) to the module.exports object by writing a single module.exports statement.

在这里,你使用的对象文字符号,并加入两种功能- calculateAreacalculateCircumference (一次性)的module.exports对象通过写一个module.exports声明。

If you check the output of this code, you will get the same result as you got earlier when using method 1.

如果检查此代码的输出,则将获得与使用方法1时获得的结果相同的结果。

Method 3:(Adding properties to the module.exports object while defining constructs)

方法3:( 在定义构造时将属性添加到module.exports对象)

In this method, you can add the constructs to the module.exports object while defining them. Let’s see how this method can be adopted in our circle module.

在此方法中,可以在定义结构时将其添加到module.exports对象。 让我们看看如何在我们的circle模块中采用这种方法。

In the code given above, you can see that the functions in the module are added to the module.exports object when they are being defined. Let’s look at how this is working. You are adding a key calculateArea to the module.exports object and the value corresponding to this key is the function definition.

在上面给出的代码中,您可以看到模块中的功能在定义时已添加到module.exports对象中。 让我们看看它是如何工作的。 您正在将一个关键calculateArea添加到module.exports对象,并且与该关键相对应的值是函数定义。

Note that the function no longer has any name and is an anonymous function which is just treated as a value to a key of an object. Thus, this function cannot be referenced to in the circle module and you cannot invoke this function inside this module by writing the following statement:

请注意,该函数不再具有任何名称,而是一个匿名函数,仅被视为对象键的值。 因此,无法在circle模块中引用此函数,并且无法通过编写以下语句在此模块内部调用此函数:

calculateArea(8);

If you try to execute the above statement, you will get a ReferenceError stating calculateArea is not defined.

如果您尝试执行上述语句,则会得到一个ReferenceError指出calculateArea is not defined

Now that you have learned how you can specify what needs to be exported from a module, how do you think the other module will be able to use the exported stuff? You need to import the module to some other module so as to be able to use the exported stuff from the former in the latter. This is when we need to discuss another parameter named require.

既然您已经了解了如何指定需要从一个模块导出的内容,那么您如何看待另一个模块将能够使用导出的内容? 您需要将模块导入到其他模块,以便能够使用后者中的前者导出的内容。 这是我们需要讨论另一个名为require参数的时候。

要求 (require)

require keyword refers to a function which is used to import all the constructs exported using the module.exports object from another module. If you have a module x in which you are exporting some constructs using the module.exports object and you want to import these exported constructs in module y, you then need to require the module x in the module y using the require function. The value returned by the require function in module y is equal to the module.exports object in the module x.

require关键字是指用于导入从另一个模块使用module.exports对象导出的所有构造的函数。 如果您有一个要使用module.exports对象在其中导出某些构造的模块x ,并且要在模块y中导入这些导出的构造,则需要使用require函数在模块y中要求该模块x 。 模块y中 require函数返回的值等于模块x中module.exports对象。

Let’s understand this using the example which we discussed earlier. You already have the circle module from which you are exporting the functions calculateArea and calculateCircumference. Now, let’s see how you can use the require function to import the exported stuff in another module.

让我们使用我们前面讨论的示例来理解这一点。 您已经有一个circle模块,可以从中导出函数calculateAreacalculateCircumference 。 现在,让我们看看如何使用require函数将导出的内容导入另一个模块。

Let’s first create a new file wherein you will be using the exported code from the circle module. Let’s name this file app.js and you can call it the app module.

首先创建一个新文件,其中将使用来自circle模块的导出代码。 我们将此文件命名为app.js ,您可以将其称为app模块。

The objective is to import into the app module all the code exported from the circle module. So, how can you include your code written in one module inside another module?

目的是将从circle模块导出的所有代码导入到app模块中。 那么,如何将编写在一个模块中的代码包含在另一个模块中呢?

Consider the syntax of the require function given below:

考虑下面给出的require函数的语法:

const variableToHoldExportedStuff = require('idOrPathOfModule');

The require function takes in an argument which can be an ID or a path. The ID refers to the id (or name) of the module needed. You should provide ID as an argument when you are using the third-party modules or core modules provided by the Node Package Manager. On the other hand, when you have custom modules defined by you, you should provide the path of the module as the argument. You can read more about the require function from this link.

require函数接受一个参数,该参数可以是ID或路径。 ID是指所需模块的ID(或名称)。 使用Node Package Manager提供的第三方模块或核心模块时,应提供ID作为参数。 另一方面,当您定义了自定义模块时,应提供模块的路径作为参数。 你可以关于从需要功能此链接。

Because you’ve already defined a custom module named circle, you’ll provide the path as an argument to the require function.

因为您已经定义了一个名为circle的自定义模块,所以您将提供路径作为require函数的参数。

app.js

app.js

If you notice clearly, the dot at the start of the path means that it is a relative path and that the modules app and circle are stored at the same path.

如果您清楚地注意到,路径开头的点表示它是相对路径,并且模块appcircle存储在同一路径中。

Let’s log on to the console the circle variable, which contains the result returned by the require function. Let’s see what is contained inside this variable.

让我们将circle变量登录到控制台,该变量包含require函数返回的结果。 让我们看看该变量中包含什么。

app.js

app.js

Check the output by saving all your code and running the following command in your Terminal (latter isn’t required if you have nodemon package installed):

通过保存所有代码并在终端中运行以下命令来检查输出(如果已安装nodemon软件包,则nodemon ):

node app

Output:

输出:

{ calculateArea: [Function: calculateArea],calculateCircumference: [Function: calculateCircumference] }

As you can see, the require function returns an object, the keys of which are the names of the variables/functions that have been exported from the required module (circle). In short, the require function returns the module.exports object.

如您所见, require函数返回一个对象,其键是已从所需模块( circle )导出的变量/函数的名称。 简而言之, require函数返回module.exports对象。

Let’s now access the functions imported from the circle module.

现在,让我们访问从circle模块导入的功能。

app.js

app.js

Output:

输出:

Area = 200.96, Circumference = 50.24

What do you think will happen if I try to access the variable named PI defined in the circle module inside the app module?

如果我尝试访问在app模块内部的circle模块中定义的名为PI的变量,您会怎么办?

app.js

app.js

Output:

输出:

Area = 200.96, Circumference = 50.24pi = undefined

Can you figure out why pi is undefined? Well, this is because the variable PI is not exported from the circle module. Remember the point where I told you that you cannot access the code written inside a module in another module for all the code written inside a module is private to it unless exported? Here, you are trying to access something which has not been exported from the circle module and is private to it.

您能找出为什么piundefined吗? 好吧,这是因为变量PI没有从circle模块导出。 还记得我曾告诉您的问题,您不能访问另一个模块中写在模块中的代码,因为除非导出,否则写在模块中的所有代码都是私有的? 在这里,您尝试访问的内容尚未从circle模块导出,并且是私有的。

So, you may be wondering why you didn’t get a ReferenceError. This is because you are trying to access a key named PI inside the module.exports object returned by the require function. You also know that the key named PI does not exist in the module.exports object.

因此,您可能想知道为什么没有得到ReferenceError 。 这是因为您试图访问require函数返回的module.exports对象内名为PI的键。 您还知道,名为PI的键在module.exports对象中不存在。

Note that when you try to access a non-existent key in an object, you get the result as undefined. This is the reason why you get PI as undefined instead of getting a ReferenceError.

请注意,当您尝试访问对象中不存在的键时,结果为undefined 。 这就是为什么您将PI设为undefined而不是得到ReferenceError

Now, let’s export the variable PI from the circle module and see if the answer changes.

现在,让我们从circle模块中导出变量PI ,看看答案是否改变。

circle.js

circle.js

Notice that here, you are not using the name of the variable PI as the key of the property added to the module.exports object. You are, instead, using another name, which is lifeOfPi.

请注意,此处没有使用变量PI的名称作为添加到module.exports对象的属性的键。 相反,您使用的是另一个名称,即lifeOfPi

This is an interesting thing to note. When you are exporting some coding construct, you can give any name to the key when adding a property added to the module.exports object. It is not mandatory to use the same name as the name you used while defining the construct. This is because you can use any valid identifier as the key in a Javascript object. Thus, on the left side of the assignment operator, you can use any valid identifier, but on the right side of the assignment operator, you need to provide a value which is defined as a construct in the scope of the current module (as you’ve defined the variables and functions in the ‘circle’ module).

这是一个有趣的事情。 导出某些编码构造时,在添加添加到module.exports对象的属性时,可以为键指定任何名称。 使用与定义结构时使用的名称相同的名称不是强制性的。 这是因为您可以将任何有效的标识符用作Javascript对象中的键。 因此,在赋值运算符的左侧,您可以使用任何有效的标识符,但是在赋值运算符的右侧,您需要提供一个值,该值被定义为当前模块范围内的构造(已在“圆圈”模块中定义了变量和函数)。

An important point to be noted is that while importing something from another module in the current module, you need to use the same key which you used while exporting it.

需要注意的重要一点是,从当前模块中的另一个模块导入内容时,需要使用与导出时相同的密钥。

app.js

app.js

Because you used the key lifeOfPi, you need to use the same key to access the variable PI defined in the circle module, as is done in the code given above.

因为您使用的是lifeOfPi键,所以您需要使用相同的键来访问circle模块中定义的变量PI ,就像上面给出的代码一样。

Output:

输出:

Area = 200.96, Circumference = 50.24pi = 3.14

What do you think will happen if you use the name of the variable instead of using the key which was used while exporting? In short, let’s try to access PI (name of the variable) instead of lifeOfPi (key used while exporting PI).

如果您使用变量的名称而不是使用导出时使用的键,您会怎么办? 简而言之,让我们尝试访问PI (变量的名称),而不是lifeOfPi (导出PI使用的键)。

app.js

app.js

Output:

输出:

Area = 200.96, Circumference = 50.24pi = undefined

This happens because the module.exports object does not know the variable PI anymore. It just knows about the keys added to it. Because the key used for exporting the variable PI is lifeOfPi, the latter can only be used to access the former.

发生这种情况是因为module.exports对象不再知道变量PI 。 它只知道添加到其中的键。 因为用于导出变量PI的密钥是lifeOfPi ,所以后者只能用于访问前者。

TL; DR (TL;DR)

  • Each file in Node.js is referred to as a module.

    Node.js中的每个文件都称为一个模块

  • Before executing the code written in a module, Node.js takes the entire code written inside the module and converts it into a function wrapper, which has the following syntax:

    在执行写在模块中的代码之前,Node.js会获取写在模块内的全部代码,并将其转换为具有以下语法的函数包装器:

(function(exports, require, module, __filename, __dirname) { // entire module code lives in here});

  • The function wrapper ensures that all the code written inside a module is private to it unless explicitly stated otherwise (exported). The parameters exports, require, module, __filename, and __dirname act as the variables global to the entire code in a module. Since each module has a function wrapper of its own, the code written inside one function wrapper becomes local to that function wrapper (read module) and is not accessible inside another function wrapper (read module).

    函数包装器确保模块内编写的所有代码均为该模块专用,除非另有明确说明(导出)。 参数exports , require , module , __filename__dirname全球的模块整个代码中的变量行为。 由于每个模块都有自己的功能包装器,因此在一个功能包装器中编写的代码将成为该功能包装器(读取模块)的本地代码,而在另一个功能包装器(读取模块)中不可访问。

  • module keyword refers to the object representing the current module. The module object has a key named exports. module.exports is another object which is used for defining what can be exported by a module and can be made available to other modules. In short, if a module wants to export something, it should be added to the module.exports object.

    module关键字是指代表当前模块的对象。 module对象有一个名为exports的键。 module.exports是另一个对象,用于定义模块可以导出的内容以及可用于其他模块的内容。 简而言之,如果模块要导出某些内容,则应将其添加到module.exports对象。

  • The default value of module.exports object is {}.

    module.exports对象的默认值为{}

  • There are three methods in which you can export something from a module, or add something to the module.exports object:

    您可以通过三种方法从模块中导出某些内容,或将某些内容添加到module.exports对象中:

    1. Define all the constructs first and then use multiple

    1.首先定义所有构造,然后使用多个

    module.exports statements where each statement is used to export a construct.

    module.exports语句,其中每个语句都用于导出构造。

    2. Define all the constructs first and then use a single

    2.首先定义所有构造,然后使用一个

    module.exports statement to exports all constructs at once following object literal notation.

    module.exports语句按照对象文字符号一次导出所有构造。

    3. Add constructs to the

    3.将构造添加到

    module.exports object while defining them.

    定义它们时, module.exports对象。

  • require keyword refers to a function which is used to import all the variables and functions exported using the module.exports object from another module. In short, if a file wants to import something it has to declare it using the following syntax:

    require关键字指的是一个函数,该函数用于导入从另一个模块使用module.exports对象导出的所有变量和函数。 简而言之,如果文件要导入某些内容,则必须使用以下语法对其进行声明:

require('idOrPathOfModule');

  • While exporting something from a module, you can use any valid identifier. It is not mandatory that you need to give the exact name of the variable/function as the key of the property added to module.exports object. Just make sure that you use the same key for accessing something which you used while exporting it.

    从模块导出内容时,可以使用任何有效的标识符。 您不必提供确切的变量/函数名称作为添加到module.exports对象的属性的键。 只需确保使用相同的密钥即可访问导出时使用的密钥。

翻译自: https://www.freecodecamp.org/news/require-module-in-node-js-everything-about-module-require-ccccd3ad383/

node.js中模块



推荐阅读
author-avatar
白堤柳帘佳_688
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有